Python Language Reference > 5. The import system

한 모듈의 Python 코드는 가져오는 프로세스를 통해 다른 모듈의 코드에 액세스할 수 있습니다. import 문은 import 기계를 호출하는 가장 일반적인 방법이지만 유일한 방법은 아닙니다. importlib.import_module() 및 내장 __import__()와 같은 함수를 사용하여 가져오기 기계를 호출할 수도 있습니다.

import 문은 두 가지 작업을 결합합니다. 명명된 모듈을 검색한 다음 해당 검색 결과를 로컬 범위의 이름에 바인딩합니다. import 문의 검색 작업은 적절한 인수와 함께 __import__() 함수에 대한 호출로 정의됩니다. __import__()의 반환 값은 import 문의 이름 바인딩 작업을 수행하는 데 사용됩니다. 해당 이름 바인딩 작업에 대한 정확한 세부 정보는 import 문을 참조하십시오.

__import__() 에 대한 직접 호출은 모듈 검색과 모듈 생성 작업만 수행합니다. 부모 패키지 가져오기 및 다양한 캐시(sys.modules 포함) 업데이트와 같은 특정 부작용이 발생할 수 있지만 import 문만 이름 바인딩 작업을 수행합니다.

import 문이 실행되면 표준 내장 __import__() 함수가 호출됩니다. 가져오기 시스템을 호출하는 다른 메커니즘(예: importlib.import_module())은 __import__()를 우회하고 자체 솔루션을 사용하여 가져오기 의미 체계를 구현하도록 선택할 수 있습니다.

모듈을 처음 가져올 때 Python은 모듈을 검색하고 발견되면 모듈 객체 1을 생성하여 초기화합니다. 명명된 모듈을 찾을 수 없으면 ModuleNotFoundError가 발생합니다. Python은 가져오기 기계가 호출될 때 명명된 모듈을 검색하기 위한 다양한 전략을 구현합니다. 이러한 전략은 아래 섹션에 설명된 다양한 후크를 사용하여 수정하고 확장할 수 있습니다.

버전 3.3에서 변경: 가져오기 시스템이 PEP 302의 두 번째 단계를 완전히 구현하도록 업데이트되었습니다. 더 이상 암시적인 가져오기 기계가 없습니다. 전체 가져오기 시스템은 sys.meta_path를 통해 노출됩니다. 또한 기본 네임스페이스 패키지 지원이 구현되었습니다(PEP 420 참조).

5.1. importlib

importlib 모듈은 가져오기 시스템과 상호 작용하기 위한 풍부한 API를 제공합니다. 예를 들어 importlib.import_module()은 가져오기 기계를 호출하기 위해 내장된 __import__()보다 간단하고 권장되는 API를 제공합니다. 자세한 내용은 importlib 라이브러리 설명서를 참조하십시오.

5.2. Packages

파이썬에는 한 가지 유형의 모듈 객체만 있으며 모든 모듈은 모듈이 파이썬, C 또는 다른 것으로 구현되었는지 여부에 관계없이 이 유형입니다. 모듈 구성을 돕고 명명 계층 구조를 제공하기 위해 Python에는 패키지 개념이 있습니다.

패키지를 파일 시스템의 디렉토리로, 모듈을 디렉토리 내의 파일로 생각할 수 있지만 패키지와 모듈이 파일 시스템에서 생성될 필요가 없으므로 이 비유를 너무 문자 그대로 받아들이지 마십시오. 이 설명서의 목적을 위해 디렉터리와 파일의 편리한 비유를 사용합니다. 파일 시스템 디렉토리와 마찬가지로 패키지는 계층적으로 구성되며 패키지 자체에는 일반 모듈뿐만 아니라 하위 패키지가 포함될 수 있습니다.

모든 패키지는 모듈이지만 모든 모듈이 패키지는 아니라는 점을 기억하는 것이 중요합니다. 달리 말하면 패키지는 특별한 종류의 모듈일 뿐입니다. 특히 path 속성을 포함하는 모든 모듈은 패키지로 간주됩니다.

모든 모듈에는 이름이 있습니다. 하위 패키지 이름은 Python의 표준 속성 액세스 구문과 유사하게 점으로 상위 패키지 이름과 구분됩니다. 따라서 email이라는 패키지가 있을 수 있습니다. 이 패키지에는 email.mime이라는 하위 패키지와 email.mime.text라는 하위 패키지 내의 모듈이 있습니다.

5.2.1. Regular packages

Python은 일반 패키지와 네임스페이스 패키지의 두 가지 유형의 패키지를 정의합니다. 일반 패키지는 Python 3.2 및 이전 버전에 존재했던 전통적인 패키지입니다. 일반 패키지는 일반적으로 __init__.py 파일을 포함하는 디렉토리로 구현됩니다. 일반 패키지를 가져오면 이 __init__.py 파일이 암시적으로 실행되고 이 파일이 정의하는 개체는 패키지 네임스페이스의 이름에 바인딩됩니다. __init__.py 파일은 다른 모듈이 포함할 수 있는 것과 동일한 Python 코드를 포함할 수 있으며 Python은 모듈을 가져올 때 모듈에 몇 가지 추가 특성을 추가합니다.

예를 들어 다음 파일 시스템 레이아웃은 3개의 하위 패키지가 있는 최상위 상위 패키지를 정의합니다.

parent/
    __init__.py
    one/
        __init__.py
    two/
        __init__.py
    three/
        __init__.py

parent.one을 가져오면 암시적으로 parent/__init__.py 및 parent/one/__init__.py가 실행됩니다. 이후에 parent.two 또는 parent.three를 가져오면 각각 parent/two/__init__.py 및 parent/three/__init__.py가 실행됩니다.

5.2.2. Namespace packages

네임스페이스 패키지는 각 부분이 하위 패키지를 상위 패키지에 제공하는 다양한 부분의 합성물입니다. 부분은 파일 시스템의 다른 위치에 있을 수 있습니다. 일부는 zip 파일, 네트워크 또는 Python이 가져오는 동안 검색하는 다른 모든 곳에서 찾을 수 있습니다. 네임스페이스 패키지는 파일 시스템의 객체에 직접적으로 대응할 수도 있고 그렇지 않을 수도 있습니다. 구체적인 표현이 없는 가상 모듈일 수 있습니다.

네임스페이스 패키지는 __path__ 속성에 일반 목록을 사용하지 않습니다. 대신 부모 패키지의 경로(또는 최상위 패키지의 경우 sys.path)가 변경되는 경우 해당 패키지 내에서 다음 가져오기 시도에서 패키지 부분에 대한 새로운 검색을 자동으로 수행하는 사용자 정의 반복 가능 유형을 사용합니다.

네임스페이스 패키지에는 parent/__init__.py 파일이 없습니다. 실제로 가져오기 검색 중에 여러 개의 상위 디렉토리가 있을 수 있으며 각 디렉토리는 다른 부분에서 제공됩니다. 따라서 parent/one은 물리적으로 parent/two 옆에 위치하지 않을 수 있습니다. 이 경우 Python은 상위 패키지 또는 하위 패키지 중 하나를 가져올 때마다 최상위 상위 패키지에 대한 네임스페이스 패키지를 생성합니다.

네임스페이스 패키지 사양에 대해서는 PEP 420도 참조하십시오.

5.3. Searching

검색을 시작하려면 Python은 가져오는 모듈(또는 패키지, 그러나 이 논의의 목적상 그 차이는 중요하지 않음)의 정규화된 이름이 필요합니다. 이 이름은 import 문에 대한 다양한 인수에서 가져오거나 importlib.import_module() 또는 __import__() 함수에 대한 매개변수에서 가져올 수 있습니다.

이 이름은 가져오기 검색의 다양한 단계에서 사용되며 하위 모듈에 대한 점으로 구분된 경로일 수 있습니다. foo.bar.baz. 이 경우 Python은 먼저 foo, foo.bar, 마지막으로 foo.bar.baz를 가져오려고 시도합니다. 중간 가져오기 중 하나라도 실패하면 ModuleNotFoundError가 발생합니다.

5.3.1. The module cache

가져오기 검색 시 가장 먼저 확인하는 곳은 sys.modules입니다. 이 매핑은 중간 경로를 포함하여 이전에 가져온 모든 모듈의 캐시 역할을 합니다. 따라서 이전에 foo.bar.baz를 가져온 경우 sys.modules에는 foo, foo.bar 및 foo.bar.baz에 대한 항목이 포함됩니다. 각 키는 해당 모듈 개체의 값을 갖습니다.

가져오는 동안 모듈 이름은 sys.modules에서 조회되며, 있는 경우 관련 값은 가져오기를 충족하는 모듈이고 프로세스가 완료됩니다. 그러나 값이 None이면 ModuleNotFoundError가 발생합니다. 모듈 이름이 없으면 Python은 계속해서 모듈을 검색합니다.

sys.modules는 쓰기 가능합니다. 키를 삭제하면 연결된 모듈이 파괴되지 않을 수 있지만(다른 모듈이 키에 대한 참조를 보유할 수 있으므로) 명명된 모듈의 캐시 항목을 무효화하여 Python이 다음에 가져올 때 명명된 모듈을 새로 검색하게 합니다. 키를 None으로 할당하여 ModuleNotFoundError가 발생하도록 모듈을 다음에 가져올 수도 있습니다.

그러나 모듈 개체에 대한 참조를 유지하고 sys.modules에서 해당 캐시 항목을 무효화한 다음 명명된 모듈을 다시 가져오는 것처럼 두 모듈 개체는 동일하지 않습니다. 반대로 importlib.reload()는 동일한 모듈 객체를 재사용하고 모듈의 코드를 다시 실행하여 모듈 내용을 다시 초기화합니다.

5.3.2. Finders and loaders

명명된 모듈이 sys.modules에서 발견되지 않으면 Python의 가져오기 프로토콜이 호출되어 모듈을 찾아 로드합니다. 이 프로토콜은 두 개의 개념적 개체인 파인더와 로더로 구성됩니다. 파인더의 임무는 알고 있는 전략을 사용하여 명명된 모듈을 찾을 수 있는지 여부를 결정하는 것입니다. 이 두 인터페이스를 모두 구현하는 객체를 임포터라고 합니다. 요청된 모듈을 로드할 수 있음을 발견하면 자신을 반환합니다.

Python에는 여러 기본 파인더 및 임포터가 포함되어 있습니다. 첫 번째는 내장 모듈을 찾는 방법을 알고 있고 두 번째는 고정된 모듈을 찾는 방법을 알고 있습니다. 세 번째 기본 파인더는 모듈의 가져오기 경로를 검색합니다. 가져오기 경로는 파일 시스템 경로 또는 zip 파일의 이름을 지정할 수 있는 위치 목록입니다. URL로 식별되는 리소스와 같이 찾을 수 있는 모든 리소스를 검색하도록 확장할 수도 있습니다.

가져오기 기계는 확장 가능하므로 모듈 검색의 범위와 범위를 확장하기 위해 새 파인더를 추가할 수 있습니다.

파인더는 실제로 모듈을 로드하지 않습니다. 명명된 모듈을 찾을 수 있으면 모듈의 가져오기 관련 정보를 캡슐화한 모듈 사양을 반환합니다. 그러면 가져오기 기계가 모듈을 로드할 때 사용합니다.

다음 섹션에서는 가져오기 기계를 확장하기 위해 새 항목을 만들고 등록하는 방법을 포함하여 파인더 및 로더에 대한 프로토콜을 자세히 설명합니다.

버전 3.4에서 변경: 이전 버전의 Python에서는 파인더가 로더를 직접 반환했지만 이제 로더를 포함하는 모듈 사양을 반환합니다. 로더는 가져오기 중에 계속 사용되지만 책임이 적습니다.

5.3.3. Import hooks

가져오기 기계는 확장 가능하도록 설계되었습니다. 이에 대한 기본 메커니즘은 가져오기 후크입니다. 가져오기 후크에는 메타 후크와 가져오기 경로 후크의 두 가지 유형이 있습니다.

sys.modules 캐시 조회 이외의 다른 가져오기 처리가 발생하기 전에 가져오기 처리 시작 시 메타 후크가 호출됩니다. 이를 통해 메타 후크는 sys.path 처리, 고정 모듈 또는 내장 모듈을 재정의할 수 있습니다. 메타 후크는 아래 설명된 대로 sys.meta_path에 새 파인더 객체를 추가하여 등록됩니다.

가져오기 경로 후크는 연결된 경로 항목이 만나는 지점에서 sys.path(또는 package.path) 처리의 일부로 호출됩니다. 가져오기 경로 후크는 아래 설명된 대로 sys.path_hooks에 새 콜러블을 추가하여 등록됩니다.

5.3.4. The meta path

명명된 모듈이 sys.modules에서 발견되지 않으면 Python은 다음으로 메타 경로 찾기 개체 목록이 포함된 sys.meta_path를 검색합니다. 이러한 파인더는 명명된 모듈을 처리하는 방법을 알고 있는지 확인하기 위해 쿼리됩니다. 메타 경로 찾기는 이름, 가져오기 경로 및 대상 모듈(선택 사항)의 세 가지 인수를 사용하는 find_spec()이라는 메서드를 구현해야 합니다. 메타 경로 찾기는 명명된 모듈을 처리할 수 있는지 여부를 결정하기 위해 원하는 모든 전략을 사용할 수 있습니다.

메타 경로 찾기가 명명된 모듈을 처리하는 방법을 알고 있으면 사양 개체를 반환합니다. 명명된 모듈을 처리할 수 없으면 None을 반환합니다. sys.meta_path 처리가 사양을 반환하지 않고 목록 끝에 도달하면 ModuleNotFoundError가 발생합니다. 발생하는 다른 모든 예외는 단순히 전파되어 가져오기 프로세스를 중단합니다.

메타 경로 찾기의 find_spec() 메서드는 두 개 또는 세 개의 인수로 호출됩니다. 첫 번째는 가져올 모듈의 정규화된 이름입니다(예: foo.bar.baz). 두 번째 인수는 모듈 검색에 사용할 경로 항목입니다. 최상위 모듈의 경우 두 번째 인수는 None이지만 하위 모듈 또는 하위 패키지의 경우 두 번째 인수는 상위 패키지의 __path__ 속성 값입니다. 적절한 __path__ 속성에 액세스할 수 없으면 ModuleNotFoundError가 발생합니다. 세 번째 인수는 나중에 로드할 대상이 될 기존 모듈 개체입니다. 가져오기 시스템은 다시 로드하는 동안에만 대상 모듈을 전달합니다.

단일 가져오기 요청에 대해 메타 경로를 여러 번 통과할 수 있습니다. 예를 들어 관련된 모듈 중 어느 것도 이미 캐시되지 않았다고 가정하면 foo.bar.baz를 가져오면 먼저 최상위 수준 가져오기를 수행하고 각 mpf(메타 경로 찾기)에서 mpf.find_spec(“foo”, None, None)을 호출합니다. foo를 가져온 후에는 mpf.find_spec(“foo.bar”, foo.__path__, None)을 호출하여 메타 경로를 두 번째로 순회하여 foo.bar를 가져옵니다. foo.bar를 가져오면 최종 탐색에서 mpf.find_spec(“foo.bar.baz”, foo.bar.__path__, None)을 호출합니다.

일부 메타 경로 찾기는 최상위 수준 가져오기만 지원합니다. 이러한 임포터는 None 이외의 것이 두 번째 인수로 전달될 때 항상 None을 반환합니다.

Python의 기본 sys.meta_path에는 3개의 메타 경로 찾기가 있습니다. 하나는 내장 모듈을 가져오는 방법을 알고 있고, 다른 하나는 고정된 모듈을 가져오는 방법을 알고 있으며, 다른 하나는 가져오기 경로(즉, 경로 기반 찾기)에서 모듈을 가져오는 방법을 알고 있습니다. .

버전 3.4에서 변경: 메타 경로 찾기의 find_spec() 메서드는 이제 더 이상 사용되지 않는 find_module()을 대체했습니다. 변경 없이 계속 작동하는 동안 가져오기 기계는 파인더가 find_spec()을 구현하지 않는 경우에만 이를 시도합니다.

5.4. Loading

모듈 사양이 발견되면 가져오기 기계는 모듈을 로드할 때 이를 사용합니다(및 여기에 포함된 로더). 가져오기 부분을 로드하는 동안 발생하는 대략적인 결과는 다음과 같습니다.

module = None
if spec.loader is not None and hasattr(spec.loader, 'create_module'):
    # It is assumed 'exec_module' will also be defined on the loader.
    module = spec.loader.create_module(spec)
if module is None:
    module = ModuleType(spec.name)
# The import-related module attributes get set here:
_init_module_attrs(spec, module)

if spec.loader is None:
    # unsupported
    raise ImportError
if spec.origin is None and spec.submodule_search_locations is not None:
    # namespace package
    sys.modules[spec.name] = module
elif not hasattr(spec.loader, 'exec_module'):
    module = spec.loader.load_module(spec.name)
    # Set __loader__ and __package__ if missing.
else:
    sys.modules[spec.name] = module
    try:
        spec.loader.exec_module(module)
    except BaseException:
        try:
            del sys.modules[spec.name]
        except KeyError:
            pass
        raise
return sys.modules[spec.name]

다음 세부 사항에 유의하십시오.

  • sys.modules에 주어진 이름을 가진 기존 모듈 객체가 있으면 가져오기가 이미 반환했을 것입니다.
  • 모듈은 로더가 모듈 코드를 실행하기 전에 sys.modules에 존재합니다. 이것은 모듈 코드가 (직간접적으로) 자신을 가져올 수 있기 때문에 중요합니다. 미리 sys.modules에 추가하면 최악의 경우 무제한 재귀를 방지하고 최상의 경우 다중 로드를 방지합니다.
  • 로드에 실패하면 실패한 모듈과 실패한 모듈만 sys.modules에서 제거됩니다. sys.modules 캐시에 이미 있는 모든 모듈과 부작용으로 성공적으로 로드된 모든 모듈은 캐시에 남아 있어야 합니다. 이는 실패한 모듈도 sys.modules에 남아 있는 재로딩과 대조됩니다.
  • 모듈이 생성된 후 실행되기 전에 가져오기 기계는 이후 섹션에 요약된 대로 가져오기 관련 모듈 속성(위의 의사 코드 예제에서 “_init_module_attrs”)을 설정합니다.
  • 모듈 실행은 모듈의 네임스페이스가 채워지는 중요한 로딩 순간입니다. 실행은 전적으로 로더에 위임되어 무엇을 어떻게 채울지 결정합니다.
  • 로드 중에 생성되어 exec_module()에 전달된 모듈은 가져오기 2 종료 시 반환된 모듈이 아닐 수 있습니다.

버전 3.4에서 변경: 가져오기 시스템이 로더의 상용구 책임을 인수했습니다. 이들은 이전에 importlib.abc.Loader.load_module() 메서드에 의해 수행되었습니다.

5.4.1. Loaders

모듈 로더는 로드의 중요한 기능인 모듈 실행을 제공합니다. 가져오기 기계는 실행할 모듈 개체인 단일 인수를 사용하여 importlib.abc.Loader.exec_module() 메서드를 호출합니다. exec_module()에서 반환된 모든 값은 무시됩니다.

로더는 다음 요구 사항을 충족해야 합니다.

  • 모듈이 Python 모듈(내장 모듈 또는 동적으로 로드되는 확장과 반대)인 경우 로더는 모듈의 전역 네임스페이스(module.__dict__)에서 모듈의 코드를 실행해야 합니다.
  • 로더가 모듈을 실행할 수 없는 경우, exec_module() 중에 발생한 다른 예외가 전파되더라도 ImportError를 발생시켜야 합니다.

대부분의 경우 파인더와 로더는 동일한 객체일 수 있습니다. 이러한 경우 find_spec() 메서드는 로더가 self로 설정된 사양을 반환합니다.

모듈 로더는 create_module() 메서드를 구현하여 로드하는 동안 모듈 객체를 생성하도록 선택할 수 있습니다. 모듈 사양이라는 하나의 인수를 사용하고 로드하는 동안 사용할 새 모듈 개체를 반환합니다. create_module()은 모듈 객체에 어떤 속성도 설정할 필요가 없습니다. 메서드가 None을 반환하면 가져오기 기계가 새 모듈 자체를 생성합니다.

버전 3.4에 추가: 로더의 create_module() 메서드.

버전 3.4에서 변경: load_module() 메서드는 exec_module()로 대체되었고 가져오기 기계가 로딩의 모든 상용구 책임을 맡았습니다.

기존 로더와의 호환성을 위해 가져오기 기계는 로더가 존재하고 로더가 exec_module()도 구현하지 않는 경우 로더의 load_module() 메서드를 사용합니다. 그러나 load_module()은 더 이상 사용되지 않으며 로더는 대신 exec_module()을 구현해야 합니다.

load_module() 메서드는 모듈을 실행하는 것 외에도 위에서 설명한 모든 상용구 로드 기능을 구현해야 합니다. 몇 가지 추가 설명과 함께 모든 동일한 제약 조건이 적용됩니다.

  • sys.modules에 지정된 이름을 가진 기존 모듈 개체가 있는 경우 로더는 해당 기존 모듈을 사용해야 합니다. (그렇지 않으면 importlib.reload()가 제대로 작동하지 않습니다.) 명명된 모듈이 sys.modules에 없으면 로더는 새 모듈 객체를 생성하고 sys.modules에 추가해야 합니다.
  • 무제한 재귀 또는 다중 로드를 방지하려면 로더가 모듈 코드를 실행하기 전에 모듈이 sys.modules에 있어야 합니다.
  • 로드에 실패하면 로더는 sys.modules에 삽입한 모든 모듈을 제거해야 하지만 실패한 모듈만 제거해야 하며 로더 자체가 모듈을 명시적으로 로드한 경우에만 제거해야 합니다.

버전 3.5에서 변경: exec_module()이 정의되었지만 create_module()이 정의되지 않은 경우 DeprecationWarning이 발생합니다.

버전 3.6에서 변경: exec_module()이 정의되었지만 create_module()이 정의되지 않은 경우 ImportError가 발생합니다.

버전 3.10에서 변경: load_module()을 사용하면 ImportWarning이 발생합니다.

5.4.2. Submodules

어떤 메커니즘(예: importlib API, import 또는 import-from 문 또는 내장 __import__())을 사용하여 하위 모듈이 로드되면 하위 모듈 객체에 대한 바인딩이 상위 모듈의 네임스페이스에 배치됩니다. 예를 들어, spam 패키지에 foo 하위 모듈이 있는 경우 spam.foo를 가져온 후 spam은 하위 모듈에 바인딩된 foo 속성을 갖게 됩니다. 다음과 같은 디렉토리 구조가 있다고 가정해 보겠습니다.

spam/
    __init__.py
    foo.py

spam/__init__.py에는 다음 줄이 있습니다.

from .foo import Foo

그런 다음 다음을 실행하면 foo 및 Foo에 대한 이름 바인딩이 스팸 모듈에 저장됩니다.

>>> import spam
>>> spam.foo
<module 'spam.foo' from '/tmp/imports/spam/foo.py'>
>>> spam.Foo
<class 'spam.foo.Foo'>

Python의 친숙한 이름 바인딩 규칙을 고려할 때 이것은 놀라운 것처럼 보일 수 있지만 실제로는 가져오기 시스템의 기본 기능입니다. 변하지 않는 것은 sys.modules[‘spam’] 및 sys.modules[‘spam.foo’]가 있는 경우(위의 가져오기 후와 마찬가지로) 후자가 전자의 foo 속성으로 나타나야 한다는 것입니다.

5.4.3. Module spec

가져오기 기계는 가져오는 동안, 특히 로드하기 전에 각 모듈에 대한 다양한 정보를 사용합니다. 대부분의 정보는 모든 모듈에 공통입니다. 모듈 사양의 목적은 이 가져오기 관련 정보를 모듈별로 캡슐화하는 것입니다.

가져오기 중에 사양을 사용하면 가져오기 시스템 구성 요소 간에 상태를 전송할 수 있습니다. 모듈 스펙을 생성하는 파인더와 이를 실행하는 로더 사이. 가장 중요한 것은 가져오기 기계가 로드의 상용구 작업을 수행할 수 있는 반면 모듈 사양이 없으면 로더가 그 책임을 진다는 것입니다.

모듈의 사양은 모듈 객체의 __spec__ 속성으로 노출됩니다. 모듈 사양의 내용에 대한 자세한 내용은 ModuleSpec을 참조하십시오.

버전 3.4의 새로운 기능.

5.4.4. Import-related module attributes

가져오기 기계는 로더가 모듈을 실행하기 전에 모듈의 사양에 따라 로드하는 동안 각 모듈 객체에 이러한 속성을 채웁니다.

__name__
__name__ 속성은 모듈의 정규화된 이름으로 설정되어야 합니다. 이 이름은 가져오기 시스템에서 모듈을 고유하게 식별하는 데 사용됩니다.

__loader__
__loader__ 속성은 모듈을 로드할 때 가져오기 기계가 사용한 로더 객체로 설정되어야 합니다. 이는 대부분 내부 검사용이지만 추가 로더 관련 기능(예: 로더와 연결된 데이터 가져오기)에 사용할 수 있습니다.

__package__
모듈의 __package__ 속성을 설정해야 합니다. 값은 문자열이어야 하지만 __name__과 같은 값일 수 있습니다. 모듈이 패키지인 경우 __package__ 값을 __name__으로 설정해야 합니다. 모듈이 패키지가 아닌 경우 __package__는 최상위 모듈의 경우 빈 문자열로, 하위 모듈의 경우 상위 패키지 이름으로 설정해야 합니다. 자세한 내용은 PEP 366을 참조하십시오.

이 속성은 PEP 366에 정의된 대로 기본 모듈에 대한 명시적 상대 가져오기를 계산하기 위해 __name__ 대신 사용됩니다. __spec__.parent와 동일한 값을 가질 것으로 예상됩니다.

버전 3.6에서 변경: __package__의 값은 __spec__.parent와 같을 것으로 예상됩니다.

__spec__
__spec__ 속성은 모듈을 가져올 때 사용된 모듈 사양으로 설정되어야 합니다. __spec__ 설정은 인터프리터 시작 중에 초기화된 모듈에 동일하게 적절하게 적용됩니다. 한 가지 예외는 __main__입니다. 여기서 __spec__은 경우에 따라 None으로 설정됩니다.

__package__가 정의되지 않은 경우 __spec__.parent가 폴백으로 사용됩니다.

버전 3.4의 새로운 기능.

버전 3.6에서 변경: __spec__.parent는 __package__가 정의되지 않은 경우 폴백으로 사용됩니다.

__path__
모듈이 패키지(일반 또는 네임스페이스)인 경우 모듈 객체의 __path__ 속성을 설정해야 합니다. 값은 반복 가능해야 하지만 __path__에 더 이상 의미가 없는 경우 비어 있을 수 있습니다. __path__가 비어 있지 않으면 반복될 때 문자열을 생성해야 합니다. __path__의 의미 체계에 대한 자세한 내용은 아래에 나와 있습니다.

패키지가 아닌 모듈에는 __path__ 속성이 없어야 합니다.

__file__
__cached__
__file__은 선택 사항입니다(설정된 경우 값은 문자열이어야 함). 모듈이 로드된 파일의 경로 이름(파일에서 로드된 경우) 또는 공유 라이브러리에서 동적으로 로드된 확장 모듈의 공유 라이브러리 파일 경로 이름을 나타냅니다. 인터프리터에 정적으로 연결된 C 모듈과 같은 특정 유형의 모듈에서는 누락될 수 있으며 가져오기 시스템은 의미론적 의미가 없는 경우(예: 데이터베이스에서 로드된 모듈) 설정되지 않은 상태로 두도록 선택할 수 있습니다.

__file__이 설정되면 __cached__ 속성도 설정될 수 있습니다. 이는 코드의 컴파일된 버전(예: 바이트 컴파일된 파일)의 경로입니다. 이 속성을 설정하기 위해 파일이 존재할 필요는 없습니다. 경로는 단순히 컴파일된 파일이 존재하는 위치를 가리킬 수 있습니다(PEP 3147 참조).

__file__이 설정되지 않은 경우에도 __cached__가 설정될 수 있습니다. 그러나 그 시나리오는 매우 이례적입니다. 궁극적으로 로더는 파인더가 제공하는 모듈 사양을 사용하는 것입니다(여기에서 __file__ 및 __cached__가 파생됨). 따라서 로더가 캐시된 모듈에서 로드할 수 있지만 파일에서 로드하지 않는 경우 이러한 비정형 시나리오가 적절할 수 있습니다.

5.4.5. module.__path__

정의에 따르면 모듈에 __path__ 속성이 있으면 패키지입니다.

패키지의 __path__ 속성은 하위 패키지를 가져오는 동안 사용됩니다. 가져오기 기계 내에서 sys.path와 거의 동일한 기능을 합니다. 즉, 가져오는 동안 모듈을 검색할 위치 목록을 제공합니다. 그러나 __path__는 일반적으로 sys.path보다 훨씬 더 제한적입니다.

__path__는 문자열의 이터러블이어야 하지만 비어 있을 수 있습니다. sys.path에 사용된 것과 동일한 규칙이 패키지의 __path__에도 적용되며 sys.path_hooks(아래에 설명됨)는 패키지의 __path__를 통과할 때 참조됩니다.

패키지의 __init__.py 파일은 패키지의 __path__ 속성을 설정하거나 변경할 수 있으며 이는 일반적으로 네임스페이스 패키지가 PEP 420 이전에 구현된 방식이었습니다. PEP 420을 채택함에 따라 네임스페이스 패키지는 더 이상 오직 __path__의 조작코드만 포함하고 있는 __init__.py파일을 지원할 필요가 없어졌습니다; 가져오기 기계는 네임스페이스 패키지에 대해 자동으로 __path__를 올바르게 설정합니다.

5.4.6. Module reprs

기본적으로 모든 모듈에는 사용 가능한 repr이 있지만 위에서 설정한 속성과 모듈 사양에 따라 모듈 객체의 repr을 보다 명시적으로 제어할 수 있습니다.

모듈에 사양(__spec__)이 있는 경우 가져오기 기계는 여기에서 repr을 생성하려고 시도합니다. 실패하거나 사양이 없는 경우 가져오기 시스템은 모듈에서 사용 가능한 모든 정보를 사용하여 기본 repr을 만듭니다. 누락된 정보에 대한 기본값과 함께 module.__name__, module.__file__ 및 module.__loader__를 repr에 대한 입력으로 사용하려고 시도합니다.

사용된 정확한 규칙은 다음과 같습니다.

  • 모듈에 __spec__ 속성이 있으면 사양의 정보가 repr을 생성하는 데 사용됩니다. “name”, “loader”, “origin” 및 “has_location” 속성이 참조됩니다.
  • 모듈에 __file__ 속성이 있으면 모듈의 repr의 일부로 사용됩니다.
  • 모듈에 __file__은 없지만 None이 아닌 __loader__가 있는 경우 로더의 repr이 모듈 repr의 일부로 사용됩니다.
  • 그렇지 않으면 repr에서 모듈의 __name__을 사용합니다.

버전 3.4에서 변경: loader.module_repr() 사용은 더 이상 사용되지 않으며 모듈 사양은 이제 가져오기 기계에서 모듈 repr을 생성하는 데 사용됩니다.

Python 3.3과의 역호환을 위해 모듈 repr은 정의된 경우 위에서 설명한 접근 방식을 시도하기 전에 로더의 module_repr() 메서드를 호출하여 생성됩니다. 그러나 이 방법은 더 이상 사용되지 않습니다.

버전 3.10에서 변경: module_repr() 호출은 이제 모듈의 __spec__ 속성을 사용하려고 시도한 후 __file__로 돌아가기 전에 발생합니다. module_repr()의 사용은 Python 3.12에서 중단될 예정입니다.

5.4.7. Cached bytecode invalidation

Python은 .pyc 파일에서 캐시된 바이트코드를 로드하기 전에 캐시가 소스 .py 파일로 최신인지 확인합니다. 기본적으로 Python은 소스를 작성할 때 캐시 파일에 소스의 마지막 수정 타임스탬프와 크기를 저장하여 이를 수행합니다. 런타임에 가져오기 시스템은 소스의 메타데이터와 비교하여 캐시 파일에 저장된 메타데이터를 확인하여 캐시 파일의 유효성을 검사합니다.

Python은 또한 소스 파일의 메타데이터가 아닌 콘텐츠의 해시를 저장하는 “해시 기반” 캐시 파일을 지원합니다. 해시 기반 .pyc 파일에는 선택 및 선택 해제의 두 가지 변형이 있습니다. 확인된 해시 기반 .pyc 파일의 경우 Python은 소스 파일을 해시하고 결과 해시를 캐시 파일의 해시와 비교하여 캐시 파일의 유효성을 검사합니다. 확인된 해시 기반 캐시 파일이 유효하지 않은 것으로 확인되면 Python은 파일을 재생성하고 새롭게 확인된 해시 기반 캐시 파일을 작성합니다. 확인되지 않은 해시 기반 .pyc 파일의 경우 Python은 단순히 캐시 파일이 존재하는 경우 유효하다고 가정합니다. 해시 기반 .pyc 파일 유효성 검사 동작은 –check-hash-based-pycs 플래그로 재정의될 수 있습니다.

버전 3.7에서 변경: 해시 기반 .pyc 파일을 추가했습니다. 이전에 Python은 바이트코드 캐시의 타임스탬프 기반 무효화만 지원했습니다.

5.5. The Path Based Finder

앞에서 언급했듯이 Python에는 몇 가지 기본 메타 경로 찾기가 제공됩니다. 경로 기반 파인더(PathFinder)라고 하는 이들 중 하나는 경로 항목 목록이 포함된 가져오기 경로를 검색합니다. 각 경로 항목은 모듈을 검색할 위치의 이름을 지정합니다.

경로 기반 파인더 자체는 아무것도 가져오는 방법을 모릅니다. 대신 개별 경로 항목을 순회하여 각 항목을 해당 특정 종류의 경로를 처리하는 방법을 알고 있는 경로 항목 찾기와 연결합니다.

기본 경로 항목 찾기 세트는 파일 시스템에서 모듈을 찾기 위한 모든 의미 체계를 구현하고 Python 소스 코드(.py 파일), Python 바이트 코드(.pyc 파일) 및 공유 라이브러리(예: .so 파일)와 같은 특수 파일 유형을 처리합니다. ). 표준 라이브러리의 zipimport 모듈에서 지원하는 경우 기본 경로 항목 찾기는 zip 파일에서 이러한 모든 파일 유형(공유 라이브러리 제외) 로드도 처리합니다.

경로 항목은 파일 시스템 위치로 제한될 필요가 없습니다. URL, 데이터베이스 쿼리 또는 문자열로 지정할 수 있는 기타 위치를 참조할 수 있습니다.

경로 기반 파인더는 검색 가능한 경로 항목의 유형을 확장하고 사용자 정의할 수 있도록 추가 후크 및 프로토콜을 제공합니다. 예를 들어 경로 항목을 네트워크 URL로 지원하려는 경우 HTTP 의미 체계를 구현하는 후크를 작성하여 웹에서 모듈을 찾을 수 있습니다. 이 후크(콜러블)는 아래에 설명된 프로토콜을 지원하는 경로 항목 찾기를 반환하며, 이후 웹에서 모듈에 대한 로더를 가져오는 데 사용되었습니다.

주의 사항: 이 섹션과 이전 섹션 모두 파인더라는 용어를 사용하며 메타 경로 파인더와 경로 항목 파인더라는 용어를 사용하여 이들을 구분합니다. 이 두 가지 유형의 파인더는 매우 유사하고 유사한 프로토콜을 지원하며 가져오기 프로세스 중에 유사한 방식으로 작동하지만 미묘하게 다르다는 점을 명심하는 것이 중요합니다. 특히 메타 경로 파인더는 sys.meta_path 순회를 키 오프한 것처럼 가져오기 프로세스의 시작 부분에서 작동합니다.

대조적으로, 경로 항목 찾기는 어떤 의미에서 경로 기반 찾기의 구현 세부 사항이며 실제로 경로 기반 찾기가 sys.meta_path에서 제거되면 경로 항목 찾기 의미 체계가 호출되지 않습니다.

5.5.1. Path entry finders

경로 기반 파인더는 위치가 문자열 경로 항목으로 지정된 Python 모듈 및 패키지를 찾고 로드하는 역할을 합니다. 대부분의 경로 항목은 파일 시스템의 위치를 지정하지만 이에 제한될 필요는 없습니다.

메타 경로 찾기로서 경로 기반 찾기는 이전에 설명한 find_spec() 프로토콜을 구현하지만 가져오기 경로에서 모듈을 찾고 로드하는 방법을 사용자 지정하는 데 사용할 수 있는 추가 후크를 노출합니다.

세 가지 변수는 경로 기반 파인더, sys.path, sys.path_hooks 및 sys.path_importer_cache에서 사용됩니다. 패키지 객체의 __path__ 속성도 사용됩니다. 이는 가져오기 기계를 사용자 정의할 수 있는 추가 방법을 제공합니다.

sys.path에는 모듈 및 패키지의 검색 위치를 제공하는 문자열 목록이 포함되어 있습니다. PYTHONPATH 환경 변수와 다양한 기타 설치 및 구현 관련 기본값에서 초기화됩니다. sys.path의 항목은 URL 또는 데이터베이스 쿼리와 같은 모듈을 검색해야 하는 파일 시스템, zip 파일 및 잠재적으로 다른 “위치”(사이트 모듈 참조)의 디렉터리 이름을 지정할 수 있습니다. sys.path에는 문자열만 있어야 합니다. 다른 모든 데이터 유형은 무시됩니다.

경로 기반 파인더는 메타 경로 파인더이므로 임포트 기구는 이전에 설명한 대로 경로 기반 파인더의 find_spec() 메서드를 호출하여 임포트 경로 검색을 시작합니다. find_spec()에 대한 경로 인수가 주어지면 통과할 문자열 경로 목록이 됩니다. 일반적으로 해당 패키지 내 가져오기에 대한 패키지의 __path__ 속성입니다. 경로 인수가 없음이면 최상위 수준 가져오기를 나타내며 sys.path가 사용됩니다.

경로 기반 파인더는 검색 경로의 모든 항목을 반복하고 이들 각각에 대해 경로 항목에 대한 적절한 경로 항목 파인더(PathEntryFinder)를 찾습니다. 이는 비용이 많이 드는 작업일 수 있기 때문에(예: 이 검색에 대한 stat() 호출 오버헤드가 있을 수 있음) 경로 기반 찾기는 경로 항목 찾기에 대한 캐시 매핑 경로 항목을 유지합니다. 이 캐시는 sys.path_importer_cache에서 유지 관리됩니다(이름에도 불구하고 이 캐시는 임포터 개체로 제한되지 않고 실제로 파인더 개체를 저장합니다). 이러한 방식으로 특정 경로 항목 위치의 경로 항목 찾기에 대한 비용이 많이 드는 검색은 한 번만 수행하면 됩니다. 사용자 코드는 경로 기반 파인더가 경로 항목 검색을 다시 수행하도록 강제하는 sys.path_importer_cache에서 캐시 항목을 자유롭게 제거할 수 있습니다.

캐시에 경로 항목이 없으면 경로 기반 파인더는 sys.path_hooks의 모든 콜러블을 반복합니다. 이 목록의 각 경로 항목 후크는 검색할 경로 항목인 단일 인수로 호출됩니다. 이 콜러블은 경로 항목을 처리할 수 있는 경로 항목 찾기를 반환하거나 ImportError를 발생시킬 수 있습니다. ImportError는 후크가 해당 경로 항목에 대한 경로 항목 찾기를 찾을 수 없음을 알리기 위해 경로 기반 찾기에서 사용됩니다. 예외는 무시되고 가져오기 경로 반복이 계속됩니다. 후크는 문자열 또는 바이트열 객체를 예상해야 합니다. 바이트 객체의 인코딩은 후크에 달려 있으며(예: 파일 시스템 인코딩, UTF-8 또는 다른 것일 수 있음) 후크가 인수를 디코딩할 수 없으면 ImportError를 발생시켜야 합니다.

sys.path_hooks 반복이 반환되는 경로 항목 파인더 없이 종료되면 경로 기반 파인더의 find_spec() 메서드는 sys.path_importer_cache에 None을 저장하고(이 경로 항목에 대한 파인더가 없음을 나타냄) None을 반환합니다. 메타 경로 찾기에서 모듈을 찾을 수 없습니다.

경로 항목 찾기가 sys.path_hooks의 경로 항목 후크 콜러블 중 하나에 의해 반환되는 경우 다음 프로토콜을 사용하여 찾기에 모듈 사양을 요청한 다음 모듈을 로드할 때 사용합니다.

빈 문자열로 표시된 현재 작업 디렉토리는 sys.path의 다른 항목과 약간 다르게 처리됩니다. 첫째, 현재 작업 디렉터리가 존재하지 않는 것으로 확인되면 sys.path_importer_cache에 값이 저장되지 않습니다. 둘째, 현재 작업 디렉토리의 값은 각 모듈 조회에 대해 새로 조회됩니다. 셋째, sys.path_importer_cache에 사용되고 importlib.machinery.PathFinder.find_spec()에 의해 반환된 경로는 빈 문자열이 아니라 실제 현재 작업 디렉토리가 됩니다.

5.5.2. Path entry finder protocol

모듈 및 초기화된 패키지의 가져오기를 지원하고 네임스페이스 패키지에 일부를 기여하려면 경로 항목 찾기에서 find_spec() 메서드를 구현해야 합니다.

find_spec()은 가져오는 모듈의 정규화된 이름과 (선택 사항인) 대상 모듈의 두 가지 인수를 사용합니다. find_spec()은 모듈에 대해 완전히 채워진 사양을 반환합니다. 이 사양에는 항상 “로더”가 설정되어 있습니다(한 가지 예외 포함).

사양이 네임스페이스 부분을 나타내는 가져오기 기계에 표시하기 위해 경로 항목 찾기는 “submodule_search_locations”를 부분을 포함하는 목록으로 설정합니다.

버전 3.4에서 변경: find_spec()이 find_loader() 및 find_module()을 대체했습니다. 둘 다 현재 사용되지 않지만 find_spec()이 정의되지 않은 경우에 사용됩니다.

이전 경로 항목 찾기는 find_spec() 대신 이 두 가지 사용되지 않는 메서드 중 하나를 구현할 수 있습니다. 메서드는 이전 버전과의 호환성을 위해 여전히 존중됩니다. 그러나 경로 항목 찾기에서 find_spec()이 구현되면 기존 메서드는 무시됩니다.

find_loader()는 가져올 모듈의 정규화된 이름인 하나의 인수를 사용합니다. find_loader()는 첫 번째 항목이 로더이고 두 번째 항목이 네임스페이스 부분인 2-튜플을 반환합니다.

가져오기 프로토콜의 다른 구현과의 하위 호환성을 위해 많은 경로 항목 찾기는 메타 경로 찾기가 지원하는 것과 동일한 기존 find_module() 메서드도 지원합니다. 그러나 경로 항목 찾기 find_module() 메서드는 경로 인수와 함께 호출되지 않습니다(경로 후크에 대한 초기 호출에서 적절한 경로 정보를 기록해야 함).

경로 항목 찾기의 find_module() 메서드는 경로 항목 찾기가 네임스페이스 패키지에 부분을 제공하는 것을 허용하지 않으므로 더 이상 사용되지 않습니다. 경로 항목 찾기에 find_loader() 및 find_module()이 모두 존재하는 경우 가져오기 시스템은 항상 find_module()보다 먼저 find_loader()를 호출합니다.

버전 3.10에서 변경: 가져오기 시스템에서 find_module() 및 find_loader()를 호출하면 ImportWarning이 발생합니다.

5.6. Replacing the standard import system

전체 가져오기 시스템을 교체하는 가장 신뢰할 수 있는 메커니즘은 sys.meta_path의 기본 콘텐츠를 삭제하고 사용자 정의 메타 경로 후크로 완전히 교체하는 것입니다.

가져오기 시스템에 액세스하는 다른 API에 영향을 주지 않고 가져오기 문의 동작만 변경하는 것이 허용되는 경우 내장 __import__() 함수를 교체하는 것으로 충분할 수 있습니다. 이 기술은 모듈 수준에서 해당 모듈 내 import 문의 동작만 변경하기 위해 사용할 수도 있습니다.

메타 경로의 초기 후크에서 일부 모듈 가져오기를 선택적으로 방지하려면(표준 가져오기 시스템을 완전히 비활성화하는 대신) None을 반환하는 대신 find_spec()에서 직접 ModuleNotFoundError를 발생시키는 것으로 충분합니다. 후자는 메타 경로 검색이 계속되어야 함을 나타내며 예외가 발생하면 즉시 종료됩니다.

5.7. Package Relative Imports

상대 가져오기는 선행 점을 사용합니다. 단일 선행 점은 현재 패키지부터 시작하여 상대적 가져오기를 나타냅니다. 두 개 이상의 선행 점은 현재 패키지의 상위 항목에 대한 상대적 가져오기를 나타냅니다(첫 번째 이후 점당 한 수준). 예를 들어 다음 패키지 레이아웃이 주어진 경우:

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
        moduleY.py
    subpackage2/
        __init__.py
        moduleZ.py
    moduleA.py

subpackage1/moduleX.py 또는 subpackage1/__init__.py에서 다음은 유효한 상대 가져오기입니다.

from .moduleY import spam
from .moduleY import spam as ham
from . import moduleY
from ..subpackage1 import moduleY
from ..subpackage2.moduleZ import eggs
from ..moduleA import foo

절대 가져오기는 import <> 또는 from <> import <> 구문을 사용할 수 있지만 상대적 가져오기는 두 번째 형식만 사용할 수 있습니다. 그 이유는 다음과 같습니다.

import XXX.YYY.ZZZ

XXX.YYY.ZZZ를 사용 가능한 표현식으로 노출해야 하지만 .moduleY는 유효한 표현식이 아닙니다.

5.8. Special considerations for __main__

__main__ 모듈은 파이썬의 가져오기 시스템과 관련된 특별한 경우입니다. 다른 곳에서 언급했듯이 __main__ 모듈은 sys 및 builtins와 마찬가지로 인터프리터 시작 시 직접 초기화됩니다. 그러나 이 두 가지와 달리 내장 모듈로 엄격하게 제한되지는 않습니다. 이는 __main__ 이 초기화되는 방식이 인터프리터가 호출되는 플래그 및 기타 옵션에 따라 달라지기 때문입니다.

5.8.1. __main__.__spec__

__main__이 초기화되는 방식에 따라 __main__.__spec__이 적절하게 설정되거나 None으로 설정됩니다.

-m 옵션으로 Python을 시작하면 __spec__이 해당 모듈 또는 패키지의 모듈 사양으로 설정됩니다. __spec__은 __main__ 모듈이 디렉토리, zip 파일 또는 기타 sys.path 항목 실행의 일부로 로드될 때도 채워집니다.

나머지 경우에는 __main__을 채우는 데 사용되는 코드가 가져오기 가능한 모듈과 직접 일치하지 않기 때문에 __main__.__spec__이 None으로 설정됩니다.

  • 대화식 프롬프트
  • -c 옵션
  • stdin에서 실행
  • 소스 또는 바이트코드 파일에서 직접 실행

__main__.__spec__은 파일을 기술적으로 모듈로 직접 가져올 수 있는 경우에도 마지막 경우에 항상 None입니다. __main__에서 유효한 모듈 메타데이터가 필요한 경우 -m 스위치를 사용하십시오.

또한 __main__이 임포트 가능한 모듈에 해당하고 __main__.__spec__이 그에 따라 설정된 경우에도 여전히 별개의 모듈로 간주됩니다. 이는 if __name__ == “__main__”: 검사가 보호하는 블록이 모듈이 __main__ 네임스페이스를 채우는 데 사용될 때만 실행되고 일반 가져오기 중에는 실행되지 않기 때문입니다.

5.9. References

가져오기 기계는 Python 초기부터 상당히 발전했습니다. 패키지의 원래 사양은 해당 문서 작성 이후 일부 세부 사항이 변경되었지만 여전히 읽을 수 있습니다.

sys.meta_path의 원래 사양은 PEP 302였으며 후속 확장은 PEP 420이었습니다.

PEP 420은 Python 3.3용 네임스페이스 패키지를 도입했습니다. PEP 420은 또한 find_module()의 대안으로 find_loader() 프로토콜을 도입했습니다.

PEP 366은 기본 모듈의 명시적 상대 가져오기를 위한 __package__ 속성 추가를 설명합니다.

PEP 328은 절대적이고 명시적인 상대 가져오기를 도입했으며 시맨틱에 대해 처음 제안된 __name__은 PEP 366이 결국 __package__에 대해 지정할 것입니다.

PEP 338은 실행 모듈을 스크립트로 정의합니다.

PEP 451은 사양 개체에서 모듈별 가져오기 상태의 캡슐화를 추가합니다. 또한 로더의 상용구 책임 대부분을 수입 기계로 다시 오프로드합니다. 이러한 변경 사항을 통해 가져오기 시스템에서 여러 API의 사용이 중단되고 파인더 및 로더에 새로운 메서드를 추가할 수 있습니다.

Source: https://docs.python.org/3/reference/import.html