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实现配置热加载?
背景 由于最近工作需求,需要在已有项目添加一个新功能,实现配置热加载的功能.所谓的配置热加载,也就是说当服务收到配置更新消息之后,我们不用重启服务就可以使用最新的配置去执行任务. 如何实现 下面我分别 ...
- IntelliJ IDEA 2017.3.2 热加载(Hot Swap)
一.IntelliJ IDEA 自带热加载,修改代码后点击Ctrl + F9即可 缺点:1.Ctrl + F9只对当前类重新编译加载 2.只支持构造代码块的CRUD.方法体内代码修改.资源文件内容的修 ...
- Python 模块的加载顺序
基本概念 module 模块, 一个 py 文件或以其他文件形式存在的可被导入的就是一个模块 package 包,包含有 init 文件的文件夹 relative path 相对路径,相对于某个目录的 ...
- python通过重启线程,实现服务的热加载
这个思路后来证明不能用于工作. 因为线程调用没有及时返回,所以不能用这种方式来重启服务. 但作为脑洞,也应该作个记录. import os import shutil import datetime ...
- java的热部署和热加载
ps:热部署和热加载其实是两个类似但不同的概念,之前理解不深,so,这篇文章重构了下. 一.热部署与热加载 在应用运行的时升级软件,无需重新启动的方式有两种,热部署和热加载. 对于Java应用程序来说 ...
- (译文)开始学习Webpack-应用TypeScript,配置热加载和Source Map
项目初始化:采用TypeScript 我们的版本是: $ node --version v8.5.0 $ npm --version 5.5.1 npm版本升级了,因为npm最近带来了新特性,本地会生 ...
- spring boot的热加载(hotswap)
官网上是叫hotswap,有人翻译成热部署,有人翻译成热加载 个人倾向于使用热加载在这个词,和谷歌翻译的热插拔相似. 关于个人理解 http://www.cnblogs.com/ptqueen/p/8 ...
- Webpack热加载和React(其中有关于include和exclude的路径问题)
看了几个React配合webpack的教程,大部分都因为版本问题过时了.终于找到了一个不错的教程.记录下其中的知识点. 首先万分感谢这个教程的制作者.少走了许多弯路,正在学习webpack的小伙伴可以 ...
- 原来热加载如此简单,手动写一个 Java 热加载吧
1. 什么是热加载 热加载是指可以在不重启服务的情况下让更改的代码生效,热加载可以显著的提升开发以及调试的效率,它是基于 Java 的类加载器实现的,但是由于热加载的不安全性,一般不会用于正式的生产环 ...
- gitbook 入门教程之解决windows热加载失败问题
破镜如何贴花黄 gitbook 在 Windows 系统无法热加载,总是报错! gitbook 是一款文档编写利器,可以方便地 markdown 输出成美观优雅的 html ,gitbook serv ...
随机推荐
- DesignPattern-part1
title: "modern C++ DesignPattern-Part1" date: 2018-04-03T16:06:33+08:00 lastmod: 2018-04-0 ...
- openNebula集群搭建
openNebula集群搭建 目录 openNebula集群搭建 OpenNebula概述 环境介绍及部署前准备 1. 安装步骤 1.关闭防火墙 2.配置epel源地和opennebula源 3.安装 ...
- 五分钟 k8s入门到实战--跨服务调用
背景 在做传统业务开发的时候,当我们的服务提供方有多个实例时,往往我们需要将对方的服务列表保存在本地,然后采用一定的算法进行调用:当服务提供方的列表变化时还得及时通知调用方. student: url ...
- 使用HTML一键打包APK工具打包KRPANO全景项目
"HMTL一键打包APK工具"可以把本地HTML项目或者网站打包为一个安卓应用APK文件,无需编写任何代码,支持在安卓设备上安装运行. 打包工具群:429338543 下载地址: ...
- Node.js vs. Spring Boot:Hello World 性能对决,谁更快一点?
前言: Spring Boot 在 Java 生态中备受欢迎,它是一款基于 Java 构建的轻量级服务端框架,主要用于 Web 服务.Spring Boot 的应用使得创建各类基于 Spring 的企 ...
- CSP-J/S 初赛冲刺
CSP-J/S 初赛冲刺 对于咱们信奥选手来说,会做的题要坚决不丢分,不会做的题要学会尽量多拿分,这样你的竞赛之路才能一路亨通! Linux 基础操作 文件(文件夹)操作 列出文件:ls 列出隐藏文件 ...
- Lua5.3 笔记
Lua5.3 笔记 最近用skynet,sproto通讯,完全看不懂通讯二进制是怎么写的,发现都是string这个,string那个,完全理解不来. 于是查了一下string.pack的api,和之前 ...
- 【NET 7.0、OpenGL ES】使用Silk.NET渲染MMD,并实时进行物理模拟。
有关mmd播放器,网上也有许多非常漂亮的实现,如 pmxeditor.saba.blender_mmd_tools等等.. 首先我想先介绍下我参考实现的仓库: sselecirPyM/Coocoo3D ...
- tarjan强连通分量
int scc[N],sc;//结点i所在scc的编号 int sz[N]; //强连通i的大小 //dfn(u)为搜到结点u时的次序编号 //low(u)为u或u的子树能够追溯到的最早的栈中节点的次 ...
- 多租户基于Springboot+MybatisPlus实现使用一个数据库一个表 使用字段进行数据隔离
多租户实现方式 多租户在数据存储上主要存在三种方案,分别是: 1. 独立数据库 即一个租户一个数据库,这种方案的用户数据隔离级别最高,安全性最好,但成本较高. 优点:为不同的租户提供独立的数据库,有助 ...