Python实现模块热加载的示例代码

 更新时间:2023年12月19日 09:25:31   作者:Python成长路  
这篇文章主要为大家详细介绍了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,修改文件会触发两次事件。搜到一个解决方案:不使用默认的事件触发,而是利用文件快照,每隔一段时间做一次比对。原文链接:Python神器watchdog(监控文件变化),我测试了一下效果很好。

源码

完整的源码就不放了,具体可以看: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递归调用中的坑:打印有值, 返回却None

    python递归调用中的坑:打印有值, 返回却None

    这篇文章主要介绍了python递归调用中的坑:打印有值, 返回却None,本文通过问题分析给出解决方法,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03
  • pycharm实现print输出保存到txt文件

    pycharm实现print输出保存到txt文件

    这篇文章主要介绍了pycharm实现print输出保存到txt文件,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-06-06
  • python实现简单的TCP代理服务器

    python实现简单的TCP代理服务器

    这篇文章主要介绍了python实现简单的TCP代理服务器,包含了完整的实现过程及对应的源码与说明文档下载,非常具有参考借鉴价值,需要的朋友可以参考下
    2014-10-10
  • python使用数字与字符串方法技巧

    python使用数字与字符串方法技巧

    这篇文章主要介绍了python使用数字与字符串方法技巧,文章内容介绍详细具有一的参考价值,需要的小伙伴可以参考一下
    2022-03-03
  • Python3 伪装浏览器的方法示例

    Python3 伪装浏览器的方法示例

    本篇文章主要介绍了Python3 伪装浏览器的方法示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • 机器深度学习二分类电影的情感问题

    机器深度学习二分类电影的情感问题

    这篇文章主要介绍了机器深度学习关于电影二次类的情感问题,代码详细,对理解深度学习中的二次类问题有很大的帮助,有需要学习的朋友可以看一下这篇文章
    2021-04-04
  • numpy.float32的典型用法

    numpy.float32的典型用法

    本文主要介绍了numpy.float32的典型用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-04-04
  • Python基于生成器迭代实现的八皇后问题示例

    Python基于生成器迭代实现的八皇后问题示例

    这篇文章主要介绍了Python基于生成器迭代实现的八皇后问题,简单描述了八皇后问题,并结合实例形式分析了Python基于生成器迭代解决八皇后问题的相关操作技巧,需要的朋友可以参考下
    2018-05-05
  • python绘制高斯曲线

    python绘制高斯曲线

    这篇文章主要为大家详细介绍了python绘制高斯曲线,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-02-02
  • Python办公自动化之Excel介绍

    Python办公自动化之Excel介绍

    大家好,本篇文章主要讲的是Python办公自动化之Excel介绍,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下,方便下次浏览
    2021-12-12

最新评论