Direct use of __import__() is rare, except in cases where you want to import a module whose name is only known at runtime.
本文介紹 python module 的動態載入,我們有時希望從配置檔案等地獲取要被動態載入的 module,但是所讀取的配置項通常為字串型別,無法用 import 載入,例如:
1 2 3 4 5 6 |
>>> import 'os' File "<stdin>", line 1 import 'os' ^ SyntaxError: invalid syntax |
Python 提供內建函式 __import__ 動態載入 module,__import__ 的用法如下:
1 2 |
__import__ (name[, globals[, locals[, fromlist[, level]]]]) |
- name (required): 被載入 module 的名稱
- globals (optional): 包含全域性變數的字典,該選項很少使用,採用預設值 global()
- locals (optional): 包含區域性變數的字典,內部標準實現未用到該變數,採用預設值 local()
- fromlist (Optional): 被匯入的 submodule 名稱
- level (Optional): 匯入路徑選項,預設為 -1,表示同時支援 absolute import 和 relative import
1 2 3 4 |
>>> os_module = __import__('os') >>> print os_module.path <module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'> |
事實上,import 本質上是呼叫 __import__ 載入 module 的,比如:
1 2 3 4 5 6 |
import foo 最終呼叫如下函式實現 foo = __import__('foo', globals(), locals(), [], -1) |
但如果使用不善,也容易踩坑:
1 2 3 4 5 6 |
>>> __import__("os") <module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'> >>> __import__("os.path") <module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'> |
如果輸入的引數如果帶有 “.”,採用 __import__ 直接匯入 module 容易造成意想不到的結果。 OpenStack 的 oslo.utils 封裝了 __import__,支援動態匯入 class, object 等。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
import sys import traceback def import_class(import_str): """Returns a class from a string including module and class. .. versionadded:: 0.3 """ mod_str, _sep, class_str = import_str.rpartition('.') __import__(mod_str) try: return getattr(sys.modules[mod_str], class_str) except AttributeError: raise ImportError('Class %s cannot be found (%s)' % (class_str, traceback.format_exception(*sys.exc_info()))) def import_object(import_str, *args, **kwargs): """Import a class and return an instance of it. .. versionadded:: 0.3 """ return import_class(import_str)(*args, **kwargs) def import_module(import_str): """Import a module. .. versionadded:: 0.3 """ __import__(import_str) return sys.modules[import_str] |