importlib 패키지는 Python 소스 코드로 작성된 import 문의 구현을 제공하며, 어떤 Python 인터프리터에서도 이식 가능하다는 특징이 있습니다. 또한 Python이 아닌 다른 프로그래밍 언어로 구현된 임포트 메커니즘보다 훨씬 이해하기 쉽습니다.
이 패키지는 임포트를 구현하는 데 필요한 구성 요소들을 공개하기 때문에, 개발자가 자신만의 커스텀 객체(일명 임포터(importer))를 만들어 임포트 과정에 직접 참여시키는 것도 손쉽게 할 수 있습니다.
importlib 패키지에는 import_module()이라는 핵심 함수가 있으며, 그 외에도 유용한 함수들을 제공합니다.
주요 함수 살펴보기
import_module()
이 함수는 프로그래밍 방식으로 모듈을 임포트합니다. 첫 번째 매개변수는 모듈 이름이며, 선택 사항인 두 번째 매개변수로 패키지 이름(존재하는 경우)을 지정할 수 있습니다.
invalidate_caches()
이 함수는 파인더(finder)들의 내부 캐시를 무효화합니다. 프로그램 실행 중에 새 모듈이 생성되거나 설치되었을 때, 모든 파인더가 해당 모듈의 존재를 확실히 인식하도록 하려면 반드시 이 함수를 호출해야 합니다.
reload()
이 함수는 이전에 임포트했던 모듈을 다시 로드합니다. 외부 편집기로 모듈의 소스 파일을 수정한 뒤, Python 인터프리터를 종료하지 않고도 변경된 버전을 바로 테스트하고 싶을 때 특히 유용합니다.
동적 임포트 실습 예제
먼저 module1.py와 module2.py라는 두 개의 Python 스크립트를 만들고, 아래와 같이 동일한 코드를 작성합니다.
#module1
def main():
print ('module imported', __name__)
return
if __name__=='__main__':
main()이제 importlib 패키지를 사용해 이 모듈들을 동적으로 임포트해 보겠습니다.
>>> import importlib
>>> mod=importlib.import_module('module1')
>>> mod.__name__
'module1'
>>> mod=importlib.import_module('module2')
>>> mod.__name__
'module2'
>>> mod.main()
module imported module2
>>>실행 결과를 보면 모듈 이름을 문자열로 전달하는 것만으로 런타임에 모듈이 정상적으로 임포트되는 것을 확인할 수 있습니다.
importlib의 주요 하위 모듈
importlib 패키지는 다음과 같은 하위 모듈들로 구성되어 있습니다.
importlib.abc
임포트 과정에서 사용되는 모든 핵심 추상 기반 클래스(ABC)를 담고 있는 모듈입니다. 핵심 ABC를 더 쉽게 구현할 수 있도록 돕는 일부 서브클래스도 함께 제공됩니다.
importlib.resources
Python의 임포트 시스템을 활용하여 패키지 내부에 포함된 리소스(데이터 파일 등)에 접근할 수 있게 해주는 모듈입니다.
importlib.machinery
임포트 시스템이 모듈을 찾고 로드하는 데 필요한 다양한 객체들을 포함하고 있는 모듈입니다.
importlib.util
임포터를 위한 유틸리티 코드가 들어 있는 모듈로, 임포터를 구성하는 데 도움이 되는 여러 객체와 중요한 함수들이 정의되어 있습니다.
importlib.util의 핵심 함수
find_spec()
지정된 패키지 이름을 기준으로 모듈의 명세(specification)를 찾는 함수입니다. 이름이 서브모듈(점을 포함하는 이름)인 경우 부모 모듈이 자동으로 임포트됩니다. name과 package 매개변수의 동작 방식은 import_module()과 동일합니다.
module_from_spec(spec)
spec과 spec.loader.create_module을 기반으로 새로운 모듈 객체를 생성하는 함수입니다.
종합 예제: 모듈 존재 확인 후 동적 임포트
import importlib.util
def check_module(mod):
spec = importlib.util.find_spec(mod)
if spec is None:
print('Module: {} not found'.format(mod))
return None
else:
print('Module: {} can be imported!'.format(mod))
return spec
def import_module(spec):
mod = importlib.util.module_from_spec(spec)
spec.loader.exec_module(mod)
return mod
if __name__ == '__main__':
spec = check_module('notamodule')
spec = check_module('module1')
if spec:
mod = import_module(spec)
mod.main()실행 결과
Module: notamodule not found Module: module1 can be imported! module imported module1
위 예제처럼 find_spec()으로 모듈의 존재 여부를 먼저 검사한 후, module_from_spec()과 exec_module()을 조합하면 안전하게 모듈을 동적으로 로드할 수 있습니다. 이러한 패턴은 플러그인 시스템이나 런타임에 모듈을 유연하게 불러와야 하는 상황에서 매우 유용하게 활용됩니다.