前言
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()函數,被刪除的方法不會剔除。