python 动态导入模块实现模块热更新的方法
作者:士多碧莉 发布时间:2022-07-06 17:37:56
最近有个部署需求,需要读取py文件格式的配置项,我的实现思路是把配置文件解析到内存中。主要使用两种方法:
importlib.import_module
types.ModuleType
方法1、使用 import_module 动态导包
先来看看import module使用方法。
主要有两个参数:
package:包名
name:模块名
返回 module 对象
现在开始实现动态导包,成功读取到配置项。
import importlib
settings = importlib.import_module("remote_settings")
这样子就能初步实现动态倒入了,但是我有个需求,就是我的系统好些个模块,用FOR循环导包,然后处理业务。然后问题来了,对同一个“包”导入多次,python并不会重新导入,而是返回内存缓存中该模块的地址。
下面验证一下,第一次写入a = 123,第二次写入a = "hello"。
输出结果,两次都是打印旧版本的变量,可见对同一个模块进行多次import_module,并不能实现热更新。
必须要reload,模块才会更新。
输出结果如下,动态reload后,成功获得新版本a的值。
到此基本实现初步热更新需求了,但是还有个问题:
问题一:重新加载的模块不删除旧版本在符号表中的登记项,比如旧版本中存在变量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 创建模块对象
手动创建module对象,而不是使用内存中的module对象。这种方法不需要判断是否需要重载,而且是真正的更新,会删除旧版本模块的登记项。
import types
def import_from_pyfile(filename):
d = types.ModuleType("config") # 创建一个模块对象
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,符合需求
因此,这种方法能让我们的模块实现真正的重载。
一些注意事项
无论是方法1还是方法2,都是返回一个module对象,module对象存在一些共性问题。
问题一:重新加载类不影响类的任何已存实例,已存实例将继续使用原来的定义,只有重新加载后创建的新实例使用新定义。
# 原先的 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 旺财
问题二:模块内的引用,不会被reload。比如模块configA中引用了其他模块(configB),当configB发生变化,重新加载configA,并不会对configB进行重载。
预期应该依次输出 configB version1、configBversion2,但是输出了两次configB version1,这说明了模块内的引用,不会被reload,需要手动更新它。
我这实现了一个递归更新方法,不仅对当前模块热更新,还更新里面所有的引用。
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)
日志如下:
来源:https://blog.csdn.net/weixin_40647516/article/details/126537108
猜你喜欢
- JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它基于ECMAScript的一个子集。 JSON
- 1. 前言熟悉 Django 的朋友应该知道,我们可以通过「 inspectdb 」命令将数据库表反向生成 Model 并写入到文件中去比如
- 常规循环引用内存泄漏和Closure内存泄漏 要了解javascript的内存泄漏问题,首先要了解的就是javascript的GC原理。我记
- PHP+MySQL的组合是构建网站的一个常见搭配,不过如何使用PHP通过Web访问MySQL数据库呢?下面从Web数据库架构的工作原理讲起。
- --利用T-SQL语句,实现数据库的备份与还原的功能 ----体现了SQL Server中的四个知识点: ----1. 获取SQL Serv
- 该代码用的是paramiko模块,python版本是python2.7下面上源码# -*- coding: utf-8 -*-import
- 概览因工作场景,需要在python代码里调用Jar包来实现一些功能,调研下来主要有两种方式:java -jar xx.jarJPype环境配
- function commafyback(num) { var x = num.split(','); return par
- 一、简介 transitions库pip install transitions状态机 state:状态节点transition:
- 密码强度是一个很普遍的功能,比较简单,主要是怎么制定这个强度规则。现在需要升级密码强度的验证,以前的验证比较简单,现在已经不能满足需求了,现
- 前言看到一个很有意思的项目,其实在之前就在百度飞浆等平台上看到类似的实现效果。可以将照片按照视频的表情,动起来。看一下项目给出的效果。项目地
- 前言 在我们学习C语言时,我们学了
- 调用sklearn的model_selection时,发现sklearn中没有model_selection的模块。经过检查,发现anaco
- 简述GoogleNet 和 VGG 等网络证明了,更深度的网络可以抽象出表达能力更强的特征,进而获得更强的分类能力。在深度网络中,随之网络深
- 题目:请求出任意区间[a,b]的所有素数,简单考虑实用性这道题看起来应该很easy是吧,但任意区间(这个问题有没get 到)Afanty的分
- 你知道(X)HTML中最多余的标签中是什么吗?在我看来就是这个<a>标签,不错,就是每个网站使用最多的超级链接标签<a&g
- PDO::getAttributePDO::getAttribute — 取回一个数据库连接的属性(PHP 5 >= 5.1.0, P
- 这篇文章主要介绍了Python异常继承关系和自定义异常实现代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价
- 一开始没看懂stddev是什么参数,找了一下,在tensorflow/python/ops里有random_ops,其中是这么写的:def
- Python是一种计算机程序设计语言。是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功