# test.py
import importlib
pkg = importlib.import_module('import_dir')
mod = importlib.import_module('import_dir.import_test')
print(pkg)
print(pkg.import_test)
print(mod)
pkg.import_test.f1()
mod.f1()
# import_test.py
def f1():
print("f1")
def f2():
print("f2")
# __init__.py, 이 파일을 생성해서 디렉토리를 패키지로 인식시킬 수 있습니다.
from . import import_test
__all__ = ["import_test"]
터미널 위에서 test.py 를 실행 결과는 다음과 같습니다. importlib.imort_module은 패키지와 모듈 모두를 import 할 수 있음을 확인했습니다.
root@root:~/test$ PYTHONPATH=. python3 test.py
<module 'import_dir' from '/home/test/import_dir/__init__.py'>
<module 'import_dir.import_test' from '/home/test/import_dir/import_test.py'>
<module 'import_dir.import_test' from '/home/test/import_dir/import_test.py'>
f1
f1
정상적으로 import하여 함수를 사용하였습니다.
3. __import__()를 사용하는 동적 import
파이썬 기본 내장함수인 __import__() 를 사용해서 동적 import를 할 수 있습니다.
이 코드를 실행시키면 mod1 은 import_test.py 모듈이 아닌 최상단 패키지인 import_dir 임을 알 수 있고, 아래처럼 에러 또한 발생합니다.
root@root:~/test$ PYTHONPATH=. python3 test.py
<module 'import_dir' from '/home/test/import_dir/__init__.py'>
<module 'import_dir' from '/home/test/import_dir/__init__.py'>
Traceback (most recent call last):
File "test.py", line 22, in <module>
print(mod1.f1)
AttributeError: module 'import_dir' has no attribute 'f1'
mod1 = __import__('import_dir.import_test') 로 import 할 모듈 파일인 import_test.py 를 명시했지만 return 된 것은 import_dir 패키지임을 확인할 수 있습니다. 이런 에러를 방지하기 위해서 __import__() 함수의 fromlist 옵션을 사용합니다.
fromlist 옵션에 하위 패키지, 모듈, 함수 등을 명시해야 최상단 패키지를 return 시키지 않고, 'import_dir.'import_test' 처럼 지정한 모듈(혹은 패키지 등)을 return하여 import 합니다.
root@root:~/test$ PYTHONPATH=. python3 test.py
<module 'import_dir' from '/home/test/import_dir/__init__.py'>
<module 'import_dir.import_test' from '/home/test/import_dir/import_test.py'>
<function f1 at 0x7f941cac9950>
<function f2 at 0x7f941cac99d8>
fromlist 를 사용하지 않고 import 하는 경우 모듈 파일내의 클래스, 함수, 변수등을 사용할 수 없습니다.
* 만일 mod1 = __import__('import_dir.import_test', fromlist=['f3', 'f4']) 처럼 존재하지 않는 'f3', 'f4' 같은 함수(변수 혹은 클래스 또한 마찬가지)를 넣어도 에러는 발생하지 않습니다.
** 만일 모듈의 하위에 존재하는 모든것을 import 하고 싶을 경우 fromlist=[''] 로 설정하면 됩니다.
4. getattr을 사용하는 동적 import
기본 내장 함수인 getattr 함수를 사용해서 동적 import를 할 수 있습니다. 서브 패키지, 서브 모듈의 import를 확인하기 위해 디렉토리 구조를 약간 변경하였습니다.
root@root:~/test$ PYTHONPATH=. python3 test.py
<module 'import_dir.import_test' from '/home/test/import_dir/import_test.py'>
<function f1 at 0x7f2f252f9950>
<function f2 at 0x7f2f252f99d8>
<module 'import_dir.subpkg' from '/home/test/import_dir/subpkg/__init__.py'>
<module 'import_dir.subpkg.mod_in_subpkg' from '/home/test/import_dir/subpkg/mod_in_subpkg.py'>
<function f3 at 0x7f2f252f9ae8>