1. 程式人生 > >__import__ 與動態載入 python module

__import__ 與動態載入 python module

本文介紹 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]

字串函式rpartition與partition

  這兩個函式都接收一個分割字串作為引數,將目標字串分割為兩個部分,返回一個三元元組(head,sep,tail),包含分割符。細微區別在於前者從目標字串的末尾也就是右邊開始搜尋分割符。

程式碼執行如下: