Python CLI 시작이 느릴 때, lazy import로 미룰 모듈은?

--help 한 줄을 보려는데 CLI가 파일 처리 모듈까지 불러오느라 한참 기다리게 한다. Python 3.15 lazy import로 미룰 import와 그대로 둘 import는 어떻게 가를까?

Python CLI 시작이 느릴 때, lazy import로 미룰 모듈은?
세 줄 요약
  • Python 3.15의 lazy import는 해당 이름을 처음 쓸 때까지 모듈 로딩을 미룬다.
  • 도움말에는 필요 없는 의존성이 적용 후보이며, 시작 시 필요한 등록·초기화는 즉시 실행해야 한다.
  • 도움말 출력뿐 아니라 실제 명령의 첫 실행과 의존성 오류까지 확인해야 적용 결과를 판단할 수 있다.

도움말에 필요 없는 모듈부터 늦춘다

CLI가 --help를 보여 주기 전부터 오래 기다리게 한다면, 실제 작업에만 필요한 모듈까지 시작할 때 불러오는지 살펴볼 만하다. 10월 9일 출시된 Python 3.15의 lazy import는 가져온 이름을 처음 사용하는 시점까지 모듈 로딩과 실행을 미룬다. 그 실행에서 끝내 사용하지 않는 모듈이라면 로딩 비용도 치르지 않을 수 있다.

모듈의 크기보다 언제 필요한지를 기준으로 적용 여부를 판단한다. 아래는 CLI에 적용할 때의 구분이다.

시작 시 하는 일적용 판단
특정 하위 명령에서만 쓰는 파일 처리 모듈해당 명령을 고를 때까지 미룰 후보다.
도움말을 포함해 모든 실행에서 즉시 쓰는 인자 처리바로 쓰므로 미뤄도 로딩을 피하기 어렵다.
import만으로 플러그인 목록을 채우는 모듈목록이 필요한 시점 전에 실행되도록 유지한다.

모듈 최상위에 선언하고 필요한 분기에서 처음 쓴다

언어 참조에 따르면 새 문법은 모듈 범위에서 사용한다. 다음은 압축 파일 목록을 요청할 때만 zipfile을 사용하는 구성 예시다.

import argparse
lazy import zipfile

parser = argparse.ArgumentParser()
parser.add_argument("--list-zip")
args = parser.parse_args()

if args.list_zip:
    with zipfile.ZipFile(args.list_zip) as archive:
        print("\n".join(archive.namelist()))

이 구조에서는 도움말을 처리하는 경로가 zipfile 이름에 접근하지 않는다. 압축 파일을 지정하면 그 분기에 들어가 모듈을 불러온다. 단, 다른 코드가 같은 모듈을 먼저 불러왔다면 이미 로딩돼 있을 수 있다.

lazy from package import name 형태도 가능하다. 함수 하나를 가져오더라도 처음 사용할 때는 해당 모듈 전체를 실행한다. 함수·클래스 내부나 try·except·finally 블록 안에 lazy 선언을 넣는 것은 허용되지 않는다. 함수 안의 기존 일반 import와는 구분해야 한다.

등록 작업도 미뤄지므로 import의 역할을 먼저 읽는다

플러그인 모듈이 불러와지는 순간 데코레이터로 목록에 자신을 등록한다면, import를 늦추는 변경은 등록 시점까지 바꾼다. 코드에서 그 모듈의 이름을 직접 쓰지 않고 등록된 목록만 읽는 구조라면 필요한 등록이 실행되지 않을 수 있다.

PEP 810은 이런 동작을 명시적인 초기화 함수로 옮기고 필요한 때 호출하는 방법을 제시한다. 당장 초기화 구조를 바꾸지 않는다면 해당 import를 일반 방식으로 남기는 선택도 가능하다. 기본 normal 모드를 전제로 한 판단이다.

오류가 드러나는 시점도 이동한다. 모듈이 없거나 내부 코드에 문제가 있어도 지연 선언만 지나갈 때는 발견하지 못하고, 이름을 처음 쓸 때 실패할 수 있다. 따라서 ‘도움말이 열렸다’는 결과만으로 선택 기능의 의존성까지 준비됐다고 판단해서는 안 된다.

시작 대기와 첫 작업의 시간을 따로 본다

CPython의 -X importtime은 모듈별 자체 로딩 시간과 하위 import를 포함한 누적 시간을 보여 준다. 예시 파일을 cli.py로 저장했다면 다음 두 경로를 나눠 살펴볼 수 있다. sample.zip은 실제 존재하는 압축 파일로 바꾼다.

python3.15 -X importtime cli.py --help
python3.15 -X importtime cli.py --list-zip sample.zip

로딩 기록과 함께 명령 전체의 완료 시간도 비교해야 한다. 시작 화면이 빨라져도 실제 작업의 첫 호출에서는 미뤄 둔 비용을 지불할 수 있기 때문이다. 등록 기능이 필요한 경로와 선택 의존성이 빠진 경로도 시험하면, 바뀐 실패 지점까지 확인할 수 있다.

일반 import까지 한꺼번에 지연시키는 -X lazy_imports=all도 있다. 기본값인 normal은 일반 import의 동작을 유지하면서 명시적 지연 선언을 따른다. 일부 모듈만 바꾸려는 작업이라면 전역 모드부터 켜는 것보다 적용 대상을 코드에서 드러내는 편이 변경 범위를 파악하기 쉽다.

3.14 이하도 함께 지원해야 한다면 새 문법을 그대로 넣을 수 없다. 대신 모듈 상단에 __lazy_modules__ = ["zipfile"]을 선언하고 일반 import zipfile을 쓰는 호환 방식이 있다. 3.15 이상에서는 지정한 모듈을 지연시키고 이전 버전에서는 일반 import로 실행한다. 어느 방식을 택하든, 줄어든 도움말 대기와 실제 명령의 동작을 함께 확인하는 것이 도입의 기준이다.