`runpy` — Python 모듈 위치 찾기와 실행
runpy — Python 모듈 위치 찾기와 실행
runpy 모듈은 Python 모듈을 먼저 임포트하지 않고 위치를 찾아 실행하는 데 써요. 주된 용도는 파일 시스템이 아니라 Python 모듈 네임스페이스로 스크립트를 찾도록 하는 -m 명령줄 스위치를 구현하는 거예요.
주의할 점은 이 모듈이 샌드박스 모듈이 아니라는 거예요. 모든 코드는 현재 프로세스에서 실행되고, 함수가 반환된 뒤에도 어떤 부작용(다른 모듈의 캐시된 임포트 같은 것)은 그대로 남아 있어요. 또한 실행된 코드가 정의한 함수와 클래스는 runpy 함수가 반환된 뒤에는 올바르게 동작한다는 보장이 없어요. 그런 제약이 특정 용도에서 받아들여지지 않는다면, 이 모듈보다 importlib이 더 알맞을 가능성이 높아요.
runpy 모듈은 두 함수를 제공해요.
출처: Python 표준 라이브러리
본문
runpy.run_module(*mod_name*, *init_globals=None*, *run_name=None*, *alter_sys=False*)
지정한 모듈의 코드를 실행하고, 결과로 나온 모듈의 globals 사전을 반환해요. 모듈의 코드는 먼저 표준 임포트 메커니즘(PEP 302 참고)으로 위치를 찾은 다음, 새로운 모듈 네임스페이스에서 실행돼요.
mod_name 인자는 절대 모듈 이름이어야 해요. 모듈 이름이 일반 모듈이 아니라 패키지를 가리키면 그 패키지를 임포트하고, 그 패키지 안의 __main__ 하위 모듈을 실행한 다음 결과 모듈 globals 사전을 반환해요.
선택 사전 인자 init_globals는 코드 실행 전에 모듈의 globals 사전을 미리 채우는 데 쓸 수 있어요. init_globals는 수정되지 않아요. 아래 특별 전역 변수 중 어떤 것이 init_globals에 정의돼 있어도, 그 정의는 run_module()이 덮어써요.
특별 전역 변수 __name__, __spec__, __file__, __cached__, __loader__, __package__는 모듈 코드가 실행되기 전에 globals 사전에 설정돼요(이는 최소 집합이며, 다른 변수들은 인터프리터 구현 세부 사항으로 암묵적으로 설정될 수 있어요).
__name__은 선택 인자 run_name이 None이 아니면 그것으로, 명명된 모듈이 패키지이면 mod_name + '.__main__'으로, 그 외에는 mod_name 인자로 설정돼요. __spec__은 실제로 임포트된 모듈에 맞게 설정돼요(즉 __spec__.name은 항상 mod_name 또는 mod_name + '.__main__'이고, 절대 run_name이 아니에요). __file__, __cached__, __loader__, __package__는 모듈 spec에 따라 평소처럼 설정돼요.
인자 alter_sys가 제공되어 True로 평가되면, sys.argv[0]이 __file__ 값으로 갱신되고 sys.modules[__name__]이 실행 중인 모듈의 임시 모듈 객체로 갱신돼요. 둘 다 함수가 반환되기 전에 원래 값으로 복원돼요.
이 sys 조작은 스레드에 안전하지 않아요. 다른 스레드가 부분적으로 초기화된 모듈이나 변경된 인자 목록을 볼 수 있어요. 스레드 코드에서 이 함수를 호출할 때는 sys 모듈을 건드리지 않는 걸 권장해요.
- 버전 3.1 변경:
__main__하위 모듈을 찾아 패키지를 실행하는 기능 추가. - 버전 3.2 변경:
__cached__전역 변수 추가(PEP 3147 참고). - 버전 3.4 변경: PEP 451이 추가한 모듈 spec 기능을 활용하도록 갱신. 이렇게 하면 이 방식으로 실행한 모듈의
__cached__가 올바르게 설정되고, 실제 모듈 이름이 항상__spec__.name으로 접근 가능함. - 버전 3.12 변경:
__cached__,__loader__,__package__설정이 폐기됨. 대안은ModuleSpec참고.
runpy.run_path(*path_name*, *init_globals=None*, *run_name=None*)
명명된 파일 시스템 위치의 코드를 실행하고, 결과로 나온 모듈의 globals 사전을 반환해요. CPython 명령줄에 넘기는 스크립트 이름과 마찬가지로 path_name은 Python 소스 파일, 컴파일된 바이트코드 파일, 또는 __main__ 모듈을 담은 유효한 sys.path 항목(예: 최상위 __main__.py 파일을 담은 zip 파일)을 가리킬 수 있어요.
단순 스크립트면 지정한 코드를 새 모듈 네임스페이스에서 그냥 실행해요. 유효한 sys.path 항목(보통 zip 파일이나 디렉터리)이면 그 항목을 먼저 sys.path의 맨 앞에 추가해요. 그런 다음 갱신된 경로로 __main__ 모듈을 찾아 실행해요. 지정된 위치에 그런 모듈이 없어도 sys.path의 다른 곳에 있는 기존 __main__ 항목이 호출되는 것에 대한 특별한 보호는 없다는 점을 기억하세요.
선택 사전 인자 init_globals는 코드 실행 전에 globals 사전을 미리 채우는 데 쓸 수 있어요. init_globals는 수정되지 않고, 특별 전역 변수의 정의는 run_path()가 덮어써요.
특별 전역 변수 __name__, __spec__, __file__, __cached__, __loader__, __package__는 코드 실행 전에 globals 사전에 설정돼요. __name__은 선택 인자 run_name이 None이 아니면 그것으로, 아니면 '<run_path>'로 설정돼요.
path_name이 (소스든 사전 컴파일된 바이트코드든) 스크립트 파일을 직접 가리키면 __file__은 path_name으로 설정되고, __spec__, __cached__, __loader__, __package__는 모두 None으로 설정돼요. path_name이 유효한 sys.path 항목이면 __spec__은 임포트된 __main__ 모듈에 맞게 설정되고(즉 __spec__.name은 항상 __main__), __file__, __cached__, __loader__, __package__는 모듈 spec에 따라 평소처럼 설정돼요.
sys 모듈에도 몇 가지 변경이 일어나요. 먼저 sys.path는 위에서 설명한 대로 변경될 수 있어요. sys.argv[0]은 path_name 값으로 갱신되고 sys.modules[__name__]은 실행 중인 모듈의 임시 모듈 객체로 갱신돼요. sys 항목에 대한 모든 변경은 함수가 반환되기 전에 되돌려져요.
run_module()과 달리 run_path()에서는 sys 변경이 선택 사항이 아니라는 점을 기억하세요. 그 조정이 sys.path 항목의 실행을 허용하는 데 필수적이기 때문이에요. 스레드 안전성 제약이 여전히 적용되므로, 스레드 코드에서 이 함수를 쓸 때는 임포트 락으로 직렬화하거나 별도 프로세스로 위임해야 해요.
- 버전 3.2에서 추가.
- 버전 3.4 변경: PEP 451의 모듈 spec 기능을 활용하도록 갱신.
- 버전 3.12 변경:
__cached__,__loader__,__package__설정이 폐기됨.
더 알아보기
- PEP 338 – Executing modules as scripts (Nick Coghlan 작성·구현)
- PEP 366 – Main module explicit relative imports (Nick Coghlan 작성·구현)
- PEP 451 – A ModuleSpec Type for the Import System (Eric Snow 작성·구현)
- 커맨드라인에서 같은 기능을 제공하는
-m옵션과 Command line and environment 문서 importlib.import_module()함수