특정 패키지의 모듈 검색 경로를 확장하거나, 패키지 내부에 함께 배포된 데이터 파일 같은 비코드(non-code) 리소스에 접근해야 할 때가 있습니다. 이럴 때 Python 표준 라이브러리의 pkgutil 모듈을 사용하면 됩니다.
pkgutil은 Python 패키지의 임포트(import) 규칙을 변경하거나 확장할 수 있는 다양한 함수를 제공하며, 패키지 안에 포함된 파일에서 코드가 아닌 리소스를 불러오는 기능도 지원합니다.
extend_path(path, name)
extend_path() 함수는 하나의 패키지를 구성하는 모듈들의 검색 경로를 확장해 줍니다. 기본적인 용도는 아래 코드처럼 패키지의 __init__.py 파일에 넣어두는 것입니다.
import pkgutil __path__ = pkgutil.extend_path(__path__, __name__)
extend_path()는 두 번째 인자로 전달된 패키지 이름과 동일한 이름의 하위 디렉터리를 가진 디렉터리를 sys.path에서 찾아 스캔합니다. 그런 다음 발견된 디렉터리 목록을 첫 번째 인자로 전달된 기존 path 값과 결합하여, 패키지 임포트 경로로 바로 사용할 수 있는 단일 리스트를 반환합니다.
주요 함수 살펴보기
find_loader(fullname)
전달된 fullname(모듈 전체 이름)에 해당하는 모듈 로더(loader) 객체를 반환합니다. 참고로 이 함수는 최신 Python 버전에서 권장되지 않으며, importlib.util.find_spec() 사용이 권장됩니다.
get_importer(path_item)
주어진 path_item에 대한 파인더(finder) 객체를 반환합니다. 파인더는 해당 경로에서 모듈을 찾는 역할을 담당합니다.
get_loader(module_or_name)
module_or_name에 해당하는 로더 객체를 가져옵니다. 이 함수 역시 deprecated 상태이므로 새 코드에서는 importlib 계열 API를 사용하는 것이 좋습니다.
iter_importers(fullname='')
지정된 모듈 이름에 대해 파인더(finder) 객체들을 순차적으로 생성(yield)합니다.
iter_modules(path=None, prefix='')
path에 있는 모든 서브모듈에 대한 ModuleInfo를 생성합니다. path가 None이면 sys.path에 있는 모든 최상위(top-level) 모듈을 대상으로 합니다.
>>> pk = pkgutil.iter_modules()
>>> for p in pk:
print(p[1])위 예제를 실행하면 현재 환경에서 임포트 가능한 최상위 모듈들의 이름이 하나씩 출력됩니다.
walk_packages(path=None, prefix='', onerror=None)
iter_modules()와 유사하지만 재귀적으로 동작합니다. path 아래의 모든 모듈을 깊이 우선으로 탐색하며 ModuleInfo를 생성하고, path가 None이면 접근 가능한 모든 모듈을 대상으로 합니다.
다음은 특정 패키지와 그 하위 패키지들을 재귀적으로 탐색하는 예제입니다.
import pkgutil
import sys
def explore_package(module_name):
loader = pkgutil.get_loader(module_name)
for sub_module in pkgutil.walk_packages([loader.filename]):
_, sub_module_name, _ = sub_module
qname = module_name + "." + sub_module_name
print(qname)
explore_package(qname)ModuleInfo namedtuple
ModuleInfo(module_finder, name, ispkg)는 모듈에 대한 간략한 요약 정보를 담고 있는 namedtuple입니다. 각 필드는 다음과 같습니다.
- module_finder: 해당 모듈을 찾은 파인더 객체
- name: 모듈의 이름
- ispkg: 모듈이 패키지인 경우 True, 일반 모듈인 경우 False
이처럼 pkgutil 모듈을 활용하면 패키지 구조를 동적으로 탐색하고, 검색 경로를 유연하게 확장할 수 있어 플러그인 시스템이나 자동화 도구를 개발할 때 특히 유용합니다.