Python实现模块热加载
文章目录
为什么需要热加载
在某些情况,你可能不希望关闭Python进程并重新打开,或者你无法重新启动Python,这时候就需要实现实时修改代码实时生效,而不用重新启动Python
在我的需求下,这个功能非常重要,我将Python注入到了其他进程,并作为一个线程运行。如果我想关闭Python,要么杀死Python相关的线程,要么重新启动进程,这都比较麻烦。所以当我修改完代码后,热加载代码是最方便的方法
Python中的导入机制
我们重复导入一个库时,第二次导入时并没有运行库里面的代码,比如先写一个a.py
,在里面写一行代码print("a模块加载")
,然后在写一个b.py
, 里面写两行import a
。即使你在多线程中再导入一遍a模块,也不会打印。例如下面的代码:
import a
import threading
print(id(a))
def test():
import a
print(id(a))
threading.Thread(target=test).start()
可以看到a的id是一样的,也就是同一个对象。
为什么会这样呢?这和Python的模块导入机制有关,Python会在sys.modules
这个字典里存储着所有的全局模块,当你导入一个新模块时,他会先查找sys.modules
里有没有这个模块,如果没有再导入,如果有就在当前代码增加个引用。举个最简单的例子:
a.py
print("a模块加载")
def aa():
print("a模块中的aa方法被加载")
b.py
import sys
a = sys.modules["a"]
a.aa()
c.py
import a
import b
先导入a模块,这样sys.modules
已经有了a模块,你就可以使用sys.modules["a"]
来使用a模块,它和import a
基本是一样的。如果你先import b
就会发现sys.modules
不存在a
重新导入模块1
既然知道它是先查找sys.modules
,那我在导入之前,先删除掉里面的a再导入就可以了
import a
import sys
del sys.modules["a"]
import a
这样就能重新加载模块
重新导入模块2
Python基础库也提供了一个方法重新加载模块:
import a
import importlib
importlib.reload(a)
看一下内部代码是怎么实现的:
逻辑也比较简单, 先看sys.modules
里有没有这个模块,如果有就使用_bootstrap._exec
导入模块。我们是不是也可以通过_bootstrap._exec
来重新导入模块,可以但不建议,因为下划线开头的模块或者函数都是不建议外部使用的,这些接口可能在版本更新后变动比较频繁
无法热加载的情况
__main__
模块无法热加载。当你执行python a.py
,这个a.py文件是无法热加载的,它并没有作为模块导入,在sys.modules
的名称就是__main__
如果你在__main__
使用from a import A
导入的类,即使a模块重新加载,__main__
里面的A也不会改变
热加载无法影响已经实例化的对象,比如你修改了模块里面的类代码,但是已经在__main__
里实例化了这个类对象,并且一直使用未释放,它的逻辑在热加载之后不会受影响。
函数级热加载
要想实现函数、方法乃至对象级别的热加载,得修改内存中的Python对象。有一个项目实现了这种,有兴趣的可以看:https://github.com/breuleux/jurigged
我的需求没有这么细,就不测试了
监听文件变化
我选择的是watchdog
,另一个pyinotify
不支持Windows。
watchdog
在Windows上有点小bug,修改文件会触发两次事件。搜到一个解决方案:不使用默认的事件触发,而是利用文件快照,每隔一段时间做一次比对。
源码
完整的源码就不放了,具体可以看:https://github.com/kanadeblisst00/module_hot_loading
国内仓库:http://www.pygrower.cn:21180/kanadeblisst/module_hot_loading
安装
pip install module-hot-loading
使用
from threading import Event
from module_hot_loading import monitor_dir
if __name__ == "__main__":
event = Event()
event.set()
path = "."
monitor_dir(path, event, __file__, interval=2, only_import_exist=False)
monitor_dir的参数:
- 需要监控的目录路径
- 停止监控的事件信号
- __main__的代码文件路径
- interval: 每隔几秒打一次文件快照做比对
- only_import_exist: 只重新加载已经导入的模块
效果
Python技术资源分享
小编是一名Python开发工程师,自己整理了一套 【最新的Python系统学习教程】,包括从基础的python脚本到web开发、爬虫、数据分析、数据可视化、机器学习等。
保存图片微信扫描下方CSDN官方认证二维码免费领取【保证100%免费
】
如果你是准备学习Python或者正在学习,下面这些你应该能用得上:
1、Python所有方向的学习路线
Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
2、学习软件
工欲善其事必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。
3、入门学习视频
我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。
4、实战案例
光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
5、清华编程大佬出品《漫画看学Python》
用通俗易懂的漫画,来教你学习Python,让你更容易记住,并且不会枯燥乏味。
6、Python副业兼职与全职路线
这份完整版的Python全套学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费
】
👉CSDN大礼包:《Python入门资料&实战源码&安装工具】免费领取(安全链接,放心点击)
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!