为什么需要热加载

在某些情况,你可能不希望关闭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的参数:

  1. 需要监控的目录路径
  2. 停止监控的事件信号
  3. __main__的代码文件路径
  4. interval: 每隔几秒打一次文件快照做比对
  5. only_import_exist: 只重新加载已经导入的模块

效果

Python实现模块热加载的更多相关文章

  1. 如何用Python实现配置热加载?

    背景 由于最近工作需求,需要在已有项目添加一个新功能,实现配置热加载的功能.所谓的配置热加载,也就是说当服务收到配置更新消息之后,我们不用重启服务就可以使用最新的配置去执行任务. 如何实现 下面我分别 ...

  2. IntelliJ IDEA 2017.3.2 热加载(Hot Swap)

    一.IntelliJ IDEA 自带热加载,修改代码后点击Ctrl + F9即可 缺点:1.Ctrl + F9只对当前类重新编译加载 2.只支持构造代码块的CRUD.方法体内代码修改.资源文件内容的修 ...

  3. Python 模块的加载顺序

    基本概念 module 模块, 一个 py 文件或以其他文件形式存在的可被导入的就是一个模块 package 包,包含有 init 文件的文件夹 relative path 相对路径,相对于某个目录的 ...

  4. python通过重启线程,实现服务的热加载

    这个思路后来证明不能用于工作. 因为线程调用没有及时返回,所以不能用这种方式来重启服务. 但作为脑洞,也应该作个记录. import os import shutil import datetime ...

  5. java的热部署和热加载

    ps:热部署和热加载其实是两个类似但不同的概念,之前理解不深,so,这篇文章重构了下. 一.热部署与热加载 在应用运行的时升级软件,无需重新启动的方式有两种,热部署和热加载. 对于Java应用程序来说 ...

  6. (译文)开始学习Webpack-应用TypeScript,配置热加载和Source Map

    项目初始化:采用TypeScript 我们的版本是: $ node --version v8.5.0 $ npm --version 5.5.1 npm版本升级了,因为npm最近带来了新特性,本地会生 ...

  7. spring boot的热加载(hotswap)

    官网上是叫hotswap,有人翻译成热部署,有人翻译成热加载 个人倾向于使用热加载在这个词,和谷歌翻译的热插拔相似. 关于个人理解 http://www.cnblogs.com/ptqueen/p/8 ...

  8. Webpack热加载和React(其中有关于include和exclude的路径问题)

    看了几个React配合webpack的教程,大部分都因为版本问题过时了.终于找到了一个不错的教程.记录下其中的知识点. 首先万分感谢这个教程的制作者.少走了许多弯路,正在学习webpack的小伙伴可以 ...

  9. 原来热加载如此简单,手动写一个 Java 热加载吧

    1. 什么是热加载 热加载是指可以在不重启服务的情况下让更改的代码生效,热加载可以显著的提升开发以及调试的效率,它是基于 Java 的类加载器实现的,但是由于热加载的不安全性,一般不会用于正式的生产环 ...

  10. gitbook 入门教程之解决windows热加载失败问题

    破镜如何贴花黄 gitbook 在 Windows 系统无法热加载,总是报错! gitbook 是一款文档编写利器,可以方便地 markdown 输出成美观优雅的 html ,gitbook serv ...

随机推荐

  1. CodeForces 1324F Maximum White Subtree

    题意 给定一棵\(n\)个节点的无根树,每个节点为黑色或者白色,每个点的答案为包含该点的子树(指无根子树)的白色节点数减黑色节点数的最大值 分析 对于无根树的题一般指定某一个点为根,不妨设为\(1\) ...

  2. 【matplotlib 实战】--面积图

    面积图,或称区域图,是一种随有序变量的变化,反映数值变化的统计图表. 面积图也可用于多个系列数据的比较.这时,面积图的外观看上去类似层叠的山脉,在错落有致的外形下表达数据的总量和趋势.面积图不仅可以清 ...

  3. Java自学网站--十几个网站的分析与评测

    ​简介 很多想学Java的人不知道怎样选教程,本文对Java自学网站进行评测. 本文不带主观倾向,只客观分析各个网站的区别. 第1类:大型培训机构(黑马等) 典型机构 黑马.尚硅谷.动力节点.白马.千 ...

  4. 如何使用Arduino创建摩尔斯电码生成器

    摩尔斯电码工作原理 摩尔斯电码发明于19世纪,使用非常简单的长短脉冲序列(通常为电和划)来远距离发送消息.通过将字母表中的字母编码为电和划的组合,信息可以只用一个单一的电子或声音信号来表达. 为了说明 ...

  5. FragmentStatePagerAdapter

    public abstract class FragmentStatePagerAdapter extends PagerAdapter java.lang.Object    ↳ android.s ...

  6. FFmpeg H.264编码器指南[译]

    H264 视频编码器指南 本指引着眼于x264编码器,这里假设你的FFmpeg 编译了--enable-libx264支持.如果你需要编译支持的帮助请看这篇文档:https://trac.ffmpeg ...

  7. 打造炫酷效果:用Java优雅地制作Excel迷你图

    摘要:本文由葡萄城技术团队原创并首发.转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 前言 迷你图是一种简洁而有效的数据可视化方式,常用于展示趋势和变化.它 ...

  8. .NET开源简单易用、内置集成化的控制台、支持持久性存储的任务调度框架 - Hangfire

    前言 定时任务调度应该是平时业务开发中比较常见的需求,比如说微信文章定时发布.定时更新某一个业务状态.定时删除一些冗余数据等等.今天给推荐一个.NET开源简单易用.内置集成化的控制台.支持持久性存储的 ...

  9. Java开发面试--群面专区

    目录 一.群面背景 二.群面流程 三.群面角色 四.群面细节 五.群面礼仪 六.群面话术 七.个人演讲 八.群面题型 群面也称无领导小组~ 候选人们被要求在一个相对自由的环境中展示他们的能力,并在没有 ...

  10. Windows 95 的辉煌诞生历史

    1992 年 2 月,Windows 3.1 的研发即将结束,而 Windows 团队正忙得不亦乐乎地计划他们的下一盘大棋.到了 3 月 5 日,他们终于悠哉悠哉地敲定了战略大计:横扫桌面.笔记本.移 ...