All about

개발을 진행하다 import를 사용자의 입력에 따라 동적으로 사용하고 싶은 경우가 생겼습니다. 파이썬에서 동적 import 하는 방법을 공부했고, 정리하고자 합니다.

* 모듈(module)은 클래스, 함수, 변수등을 저장한 파일, 패키지(package)는 여러 모듈을 묶은 것입니다.

 

1. Python에서 import 하는 방법들

2. importlib을 사용하는 동적 import

3. __import__()를 사용하는 동적 import

4. getattr을 사용하는 동적 import

 

1. 일반적으로 Python에서 import 하는 방법들

파이썬에서 모듈이나 패키지를 import 할 때는 보편적으로 아래처럼 하게 됩니다.

 

import pkg
import pkg.mod
from pkg import mod, mod2
from pkg.mod import func, func2
from pkg.subpkg import submod
from pkb.mod import cls

 

2. importlib을 사용하는 동적 import

importlib을 사용해서 모듈을 import 해봅니다. 먼저 실행 디렉토리 구조는 아래와 같습니다.

 

root@root:~/test$ tree .
.
├── import_dir
│   ├── import_test.py
│   ├── __init__.py
└── test.py

 

각각의 py 파일의 내용은 아래와 같습니다.

 

# 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를 할 수 있습니다.

 

# test.py
pkg = __import__('import_dir')
mod1 = __import__('import_dir.import_test')
print(pkg)
print(mod1)
print(mod1.f1)
print(mod1.f2)

 

이 코드를 실행시키면 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 합니다.

 

# test.py
pkg = __import__('import_dir')
mod1 = __import__('import_dir.import_test', fromlist=['f1', 'f2'])

print(pkg)
print(mod1)
print(mod1.f1)
print(mod1.f2)

 

이 파일을 실행해보면 정상적으로 동작하는 것을 확인할 수 있습니다.

 

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$ tree .
.
├── import_dir
│   ├── import_test.py
│   ├── __init__.py
│   └── subpkg
│       ├── __init__.py
│       ├── mod_in_subpkg.py
└── test.py

 

getattr을 사용해서 import를 해봅니다. 마지막 줄의 경우 에러를 발생시킵니다.

 

import import_dir

mod1 = getattr(import_dir, 'import_test')
subpkg = getattr(import_dir, 'subpkg')
submod = getattr(import_dir, 'subpkg.mod_in_subpkg')

 

위 코드의 Error Traceback

 

root@root:~/test$ PYTHONPATH=. python3 test.py
Traceback (most recent call last):
  File "test.py", line 53, in <module>
    submod = getattr(import_dir, 'subpkg.mod_in_subpkg')
AttributeError: module 'import_dir' has no attribute 'subpkg.mod_in_subpkg'

 

getattr의 경우 동적으로 더 깊은 depth의 모듈을 import 할 수 없음을 확인했습니다. getattr을 사용해서 import할 경우 import한 오브젝트의 하위에 존재하는 것들을 모두 사용할 수 있습니다.

 

import import_dir

mod1 = getattr(import_dir, 'import_test')
subpkg = getattr(import_dir, 'subpkg')
print(mod1)
print(mod1.f1)
print(mod1.f2)
print(subpkg)
print(subpkg.mod_in_subpkg)
print(subpkg.mod_in_subpkg.f3)

 

실행결과

 

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>

 

 

참고:

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

 

5. The import system — Python 3.9.6 documentation

Python code in one module gains access to the code in another module by the process of importing it. The import statement is the most common way of invoking the import machinery, but it is not the only way. Functions such as importlib.import_module() and b

docs.python.org

 

https://docs.python.org/3/library/importlib.html?highlight=importlib#module-importlib

 

importlib — The implementation of import — Python 3.9.6 documentation

importlib — The implementation of import Source code: Lib/importlib/__init__.py Introduction The purpose of the importlib package is two-fold. One is to provide the implementation of the import statement (and thus, by extension, the __import__() function

docs.python.org

 

공유하기

facebook twitter kakaoTalk kakaostory naver band
loading