python?動態(tài)導(dǎo)入模塊實現(xiàn)模塊熱更新的方法
最近有個部署需求,需要讀取py文件格式的配置項,我的實現(xiàn)思路是把配置文件解析到內(nèi)存中。主要使用兩種方法:
- importlib.import_module
- types.ModuleType
方法1、使用 import_module 動態(tài)導(dǎo)包
先來看看import module使用方法。
- 主要有兩個參數(shù):
- package:包名
- name:模塊名
- 返回 module 對象
現(xiàn)在開始實現(xiàn)動態(tài)導(dǎo)包,成功讀取到配置項。
import importlib settings = importlib.import_module("remote_settings")
這樣子就能初步實現(xiàn)動態(tài)倒入了,但是我有個需求,就是我的系統(tǒng)好些個模塊,用FOR循環(huán)導(dǎo)包,然后處理業(yè)務(wù)。然后問題來了,對同一個“包”導(dǎo)入多次,python并不會重新導(dǎo)入,而是返回內(nèi)存緩存中該模塊的地址。
下面驗證一下,第一次寫入a = 123,第二次寫入a = "hello"。
輸出結(jié)果,兩次都是打印舊版本的變量,可見對同一個模塊進行多次import_module,并不能實現(xiàn)熱更新。
必須要reload,模塊才會更新。
輸出結(jié)果如下,動態(tài)reload后,成功獲得新版本a的值。
到此基本實現(xiàn)初步熱更新需求了,但是還有個問題:
問題一:重新加載的模塊不刪除舊版本在符號表中的登記項,比如舊版本中存在變量a,新版本中刪除了該變量,但是重載不會更新該變化。
def load_module(module_name): module = importlib.import_module(module_name) return importlib.reload(module) def rewrite_file(file_name, content): with open(file_name, "w+") as f: f.write(content) def main(): rewrite_file(file_name, "a=123\nb=456") c1 = load_module(module_name) print(hasattr(c1, "a")) rewrite_file(file_name, "c=100\nd=200") c1 = load_module(module_name) print(hasattr(c1, "a"))
我們期望輸出 True、False,但是兩次都是輸出True,也就是說重新加載的模塊不會刪除最初舊版本模塊在符號表中的登記項。
方法2、使用types.ModuleType 創(chuàng)建模塊對象
手動創(chuàng)建module對象,而不是使用內(nèi)存中的module對象。這種方法不需要判斷是否需要重載,而且是真正的更新,會刪除舊版本模塊的登記項。
import types def import_from_pyfile(filename): d = types.ModuleType("config") # 創(chuàng)建一個模塊對象 d.__file__ = filename try: with open(filename, "r") as config_file: exec(compile(config_file.read(), filename, "exec"), d.__dict__) except ImportError as e: print("failt to read config file: {}".format(filename)) raise e return d
下面驗證一下
我們期望的輸出依次是True、False,符合需求
因此,這種方法能讓我們的模塊實現(xiàn)真正的重載。
一些注意事項
無論是方法1還是方法2,都是返回一個module對象,module對象存在一些共性問題。
問題一:重新加載類不影響類的任何已存實例,已存實例將繼續(xù)使用原來的定義,只有重新加載后創(chuàng)建的新實例使用新定義。
# 原先的 Dog 定義 # class Dog(): # def __init__(self): # self.name = None c1 = load_module(module_name) old_dog = c1.Dog() # 中間去修改了 Dog 定義 # class Dog(): # def __init__(self): # self.name = "旺財" c1 = load_module(module_name) new_dog = c1.Dog() print(old_dog.name, new_dog.name) >>> ouput: None 旺財
問題二:模塊內(nèi)的引用,不會被reload。比如模塊configA中引用了其他模塊(configB),當configB發(fā)生變化,重新加載configA,并不會對configB進行重載。
預(yù)期應(yīng)該依次輸出 configB version1、configBversion2,但是輸出了兩次configB version1,這說明了模塊內(nèi)的引用,不會被reload,需要手動更新它。
我這實現(xiàn)了一個遞歸更新方法,不僅對當前模塊熱更新,還更新里面所有的引用。
def load_module(module): if isinstance(module, str): # 首次import module = importlib.import_module(module) return importlib.reload(module) def reload_module(module): load_module(module) for key, child_module in vars(module).items(): if isinstance(child_module, types.ModuleType): reload_module(child_module)
效果如下:
def test_reload_module(): configA = "config" configB = "./configB.py" configC = "./configC.py" rewrite_file(configB, "import configC\nname ='configB version1'") rewrite_file(configC, "name ='configC version1'") confA = load_module(configA) print("原始configB.name:", confA.configB.name) print("原始configC.name:", confA.configB.configC.name) a = 123 rewrite_file(configB, "import configC\nname ='configB version2'") rewrite_file(configC, "name ='configC version2'") confA = load_module(configA) print("非遞歸重載configA, configB.name:", confA.configB.name) print("非遞歸重載configA, configC.name:", confA.configB.configC.name) reload_module(confA) print("遞歸重載configA, configB.name:", confA.configB.name) print("遞歸重載configA, configC.name:", confA.configB.configC.name)
日志如下:
到此這篇關(guān)于python動態(tài)導(dǎo)入模塊,實現(xiàn)模塊熱更新的文章就介紹到這了,更多相關(guān)python模塊熱更新內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
pandas時間序列之如何將int轉(zhuǎn)換成datetime格式
這篇文章主要介紹了pandas時間序列之如何將int轉(zhuǎn)換成datetime格式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07pytorch中節(jié)約顯卡內(nèi)存的方法和技巧
顯存不足是很多人感到頭疼的問題,畢竟能擁有大量顯存的實驗室還是少數(shù),而現(xiàn)在的模型已經(jīng)越跑越大,模型參數(shù)量和數(shù)據(jù)集也越來越大,所以這篇文章給大家總結(jié)了一些pytorch中節(jié)約顯卡內(nèi)存的方法和技巧,需要的朋友可以參考下2023-11-11pandas缺失值np.nan, np.isnan, None, pd.isnull,&n
本文主要介紹了pandas缺失值np.nan, np.isnan, None, pd.isnull, pd.isna2024-04-04Python 實現(xiàn)取多維數(shù)組第n維的前幾位
今天小編就為大家分享一篇Python 實現(xiàn)取多維數(shù)組第n維的前幾位,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-11-11