import 문이 실행되면, Python은 내장 함수 __import__()를 호출하고, 이 함수는 내부적으로 importlib._bootstrap._find_and_load() 함수를 사용하여 임포트 과정을 처리합니다. 이 과정에서 먼저 sys.modules 딕셔너리에서 모듈을 찾고, 없으면 sys.meta_path의 메타 파인더들을 순차적으로 호출하여 모듈을 검색합니다. 파인더가 모듈을 찾으면 ModuleSpec 객체를 반환하고, 이 객체를 사용하여 모듈 객체를 생성합니다. 생성된 모듈은 로더의 exec_module() 메서드로 초기화되며, 초기화 전에 sys.modules 딕셔너리에 {모듈 이름: 모듈 객체} 형태로 추가됩니다.
import foo # 기본 임포트
from foo import bar # 특정 속성만 임포트, 근데 과연 얘만? 사실 해당 파일 전부 import한다.
from foo import bar as baz # 다른 이름으로 임포트
검색(Finding): 모듈 찾기 과정
로딩(Loading): 모듈 실행 및 초기화
__import__() 함수importlib.import_module()__import__() 호출# 권장되는 방법
import importlib
module = importlib.import_module('foo.bar')
import 문으로 가져와 사용__init__.py 파일이 포함된 디렉토리parent/
__init__.py
one/
__init__.py
two/
__init__.py
__init__.py 파일이 없음path1/
parent/
one/
module1.py
path2/
parent/
two/
module2.py
| 특성 | 정규 패키지 | 네임스페이스 패키지 |
|---|---|---|
__init__.py | 필수 | 없음 |
| 위치 | 단일 디렉토리 | 여러 디렉토리 가능 |
| 초기화 코드 | 있음 | 없음 |
__file__ 속성 | 있음 | 없음 |
__path__ 속성 | 단일 경로 | 여러 경로(_NamespacePath) |
my-library-core/
mylib/
core/
__init__.py
utils.py
my-library-extras/
mylib/
extras/
__init__.py
feature.py
# 두 패키지가 설치되었을 때
from mylib.core import utils
from mylib.extras import feature
# 'mylib'은 네임스페이스 패키지
sys.modules 캐시 확인sys.meta_path의 파인더들에게 검색 요청ModuleNotFoundError 발생sys.modules)파인더: 모듈을 찾는 객체
find_spec() 메서드 구현로더: 모듈을 로드하는 객체
create_module(), exec_module() 메서드 구현sys.meta_path)find_spec() 호출sys.path와 sys.path_hooks 사용name: 모듈 이름loader: 로더 객체origin: 모듈 소스 위치submodule_search_locations: 서브모듈 검색 경로# 모듈 객체 생성
if spec.loader is not None and hasattr(spec.loader, 'create_module'):
module = spec.loader.create_module(spec)
if module is None:
module = ModuleType(spec.name)
# 모듈 속성 초기화
_init_module_attrs(spec, module)
# 모듈 등록 및 실행
sys.modules[spec.name] = module
try:
spec.loader.exec_module(module)
except BaseException:
del sys.modules[spec.name]
raise
모듈 객체 생성
create_module() 또는 기본 ModuleType모듈 속성 초기화
__name__, __loader__, __package__, __spec__ 등모듈 코드 실행
exec_module() 메서드 호출sys.modules에 먼저 등록됨 (순환 참조 방지)sys.modules에서 제거내가 zope.interface 패키지 안에서 사용자 정의 무언가를 만들고 싶어!
zope-interface-proxy/
setup.py
zope/ # 네임스페이스 패키지 (init.py 없음)
interface/ # 네임스페이스 패키지 (init.py 없음)
proxy/ # 실제 패키지
__init__.py
proxy.py
from setuptools import setup, find_namespace_packages
setup(
name="zope-interface-proxy",
version="0.1.0",
packages=find_namespace_packages(include=["zope.*"]),
namespace_packages=["zope", "zope.interface"],
)
import zope.interface.proxy
# 또는
from zope.interface.proxy import SomeClass
.)을 사용한 임포트# subpackage1/moduleX.py 내에서
from .moduleY import spam # 같은 패키지
from ..subpackage2 import moduleZ # 부모의 다른 서브패키지
from ... import moduleA # 최상위 패키지의 모듈
__main__ 모듈의 특별한 처리-m 옵션: 해당 모듈의 스펙 설정__spec__는 Noneif __name__ == "__main__": 블록은 직접 실행 시에만 작동| 속성 | 설명 |
|---|---|
__name__ | 모듈의 이름 |
__file__ | 모듈 파일의 경로 |
__package__ | 모듈이 속한 패키지 이름 |
__path__ | 패키지의 서브모듈 검색 경로 |
__spec__ | 모듈 스펙 정보 |
__loader__ | 모듈을 로드한 로더 객체 |
sys.modules)가 첫 번째 검색 대상