python筆記73-動態導入模塊import_module 和 重載reload


前言

python動態加載import_module 和 重載reload 的使用
python環境:V3.6.x

import_module

當我們在運行一段程序,根據需要動態加載一個模塊,調用里面的方法時,除了平台使用的import module,也可以在代碼里面用到import_module方法。
比如我有個模塊 yoyo.py,里面寫了個函數

def fun1():
    return "hello world"


def fun2():
    return "上海-悠悠"

a.py 需要加載yoyo.py模塊(2個文件在同一層級)

import importlib
import inspect


# 動態導入模塊
m = importlib.import_module('yoyo')
print(m)  # module object

# 調用fun1
print(m.fun1())  # hello world

# 獲取模塊全部函數
items = inspect.getmembers(m, inspect.isfunction)
print(dict(items))
# {'fun1': <function fun1 at 0x0000015CEAEA0DC0>, 'fun2': <function fun2 at 0x0000015CEAEEA670>}

運行結果:

<module 'yoyo' from 'D:\\demo\\demo\\yoyo.py'>
hello world
{'fun1': <function fun1 at 0x0000015CEAEA0DC0>, 'fun2': <function fun2 at 0x0000015CEAEEA670>}

動態更新模塊

前面importlib.import_module()導入模塊是沒有問題的,但是如果在執行的過程中 yoyo.py 模塊發生了改變,會無法加載到最新的方法。
可以在python交互環境測試次問題

D:\demo\demo>python
Python 3.6.6 (v3.6.6:4cf1f54eb7, Jun 27 2018, 03:37:03) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import importlib
>>> m = importlib.import_module('yoyo')
>>> m
<module 'yoyo' from 'D:\\demo\\demo\\yoyo.py'>
>>> m.fun1()
'hello world'
>>> m.fun2()
'上海-悠悠'
>>>

當我在yoyo.py模塊新增一個fun3()函數時,yoyo.py內容如下

def fun1():
    return "hello world"


def fun2():
    return "上海-悠悠"


def fun3():
    return "hello yoyo"

此時繼續在上面交互環境操作,調用fun3()方法

>>> m.fun3()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'yoyo' has no attribute 'fun3'
>>>

於是會看到新增的函數是無法調用的,因為在前面已經導入了模塊,模塊里面的2個函數,已經被加載進去了,后面模塊更新的內容是不會自動更新的。
那么有沒什么辦法,可以在新增方法后,重新讓系統加載一次模塊呢?這里可以用到reload() 方法,重載模塊

reload() 重載模塊

接着剛才的報錯,使用reload()重載模塊

>>> from importlib import reload
>>> new = reload('yoyo')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "E:\python36\lib\importlib\__init__.py", line 139, in reload
    raise TypeError("reload() argument must be a module")
TypeError: reload() argument must be a module
>>>

直接寫模塊名稱會出現報錯:reload() argument must be a module

看下reload()的相關源碼說明:傳的module參數必須在使用之前被成功導入過。

def reload(module):
    """Reload the module and return it.

    The module must have been successfully imported before.

    """
    if not module or not isinstance(module, types.ModuleType):
        raise TypeError("reload() argument must be a module")
    try:
        name = module.__spec__.name
    except AttributeError:
        name = module.__name__

module參數可以通過sys模塊獲取到模塊對象 sys.modules['yoyo']

>>> import sys
>>> sys.modules['yoyo']
<module 'yoyo' from 'D:\\demo\\demo\\yoyo.py'>
>>> new = importlib.reload(sys.modules['yoyo'])
>>> new.fun3()
'hello yoyo'
>>> new.fun1()
'hello world'
>>> new.fun2()
'上海-悠悠'

於是就可以成功調用到新增的fun3()方法

更新方法和刪除方法

如果更新了方法里面代碼,fun3()改成返回"123456"

def fun3():
    return "123456"

重新reload()后,代碼也會更新

>>> new = importlib.reload(sys.modules['yoyo'])
>>> new.fun3()
'123456'

如果把func3()刪除了呢?

>>> new = importlib.reload(sys.modules['yoyo'])
>>> new.fun3()
'123456'

重新reload()后,依然可以調用到fun3()函數,被刪除的方法不會剔除。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM