我的编程空间,编程开发者的网络收藏夹
学习永远不晚

python 动态导入模块实现模块热更新的方法

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

python 动态导入模块实现模块热更新的方法

最近有个部署需求,需要读取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)

日志如下:

到此这篇关于python动态导入模块,实现模块热更新的文章就介绍到这了,更多相关python模块热更新内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

python 动态导入模块实现模块热更新的方法

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Python导入模块的方法

Python导入模块的方法有两种:import module 和 from module import a,区别是前者所有导入的东西使用时需加上模块名的限定(module.a),而后者不需要。导入一个模块,Python 解析器对模块位置的搜
2023-01-30

python导入pygame模块的方法

这篇“python导入pygame模块的方法”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“python导入pygame模块的
2023-06-30

Python模块导入的几种方法

在Python语言的编辑器里,除了默认的内置函数外,其他函数的调用,必须先通过import语句将其导入才能使用。import语句导入整个函数模块导入方法: import 函数模块名示例新建一个名为func_test.py的文件,内容为:de
2023-01-30

Python导入模块的方法有哪些

这篇文章主要介绍“Python导入模块的方法有哪些”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Python导入模块的方法有哪些”文章能帮助大家解决问题。很多初学者经常遇到这样的问题,即自定义 Py
2023-07-05

python模块导入的方法有哪些

在Python中,有几种导入模块的方法,包括:1. 使用`import`语句导入整个模块:可以使用`import module_name`来导入整个模块,然后使用`module_name.function_name`来访问模块中的函数或变量
2023-08-08

python中动态加载模块和类方法实现

python中动态加载模块和类方法实现测试代码 文件名: mytest.py 具体代码如下: 注意:模块名,类名,方法名都是变量。 #coding=UTF-8class TestClass: def sub(self,a,b):
2023-01-31

Python在不同目录下导入模块的实现方法

python在不同层级目录import模块的方法 使用python进行程序编写时,经常会调用不同目录下的模块及函数。本篇博客针对常见的模块调用讲解导入模块的方法。 1. 同级目录下的调用 目录结构如下:? src |? mod1.py
2022-06-05

python中模块导入的方法有哪些

在Python中,模块导入的方法有以下几种:1. import语句:使用import关键字导入一个模块。例如:```import math```2. from...import语句:使用from关键字导入模块的一部分或者全部内容。例如:``
2023-09-13

python导入自定义模块的方法是什么

要导入自定义模块,可以使用以下方法:1. 在同一目录下导入模块:- 将自定义模块文件(.py文件)放在与主程序(调用模块的脚本)相同的目录下。- 使用`import`关键字导入模块,例如:`import module_name`2. 在不同
2023-08-29

Python中的模块导入和读取键盘输入的方法

导入模块 import 语句 想使用Python源文件,只需在另一个源文件里执行import语句,语法如下:import module1[, module2[,... moduleN]当解释器遇到import语句,如果模块在当前的搜索路径就
2022-06-04

Python中导入自定义模块的几种方法总结

这篇文章主要介绍了Python中导入自定义模块的几种方法总结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
2023-01-04

在python中实现导入一个需要传参的模块

最近跑实验,遇到了一个问题: 由于实验数据集比较多,每次跑完一个数据集就需要手动更改文件路径,再将文件传到服务器,再运行实验,这样的话效率很低,必须要专门看着这个实验,啥时候跑完就手动修改运行下一个实验。我个人无法忍受这样低效率,就想能不能
2022-06-02

Python的import 机制中如何实现远程导入模块

本篇文章为大家展示了Python的import 机制中如何实现远程导入模块,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。所谓的模块导入,是指在一个模块中使用另一个模块的代码的操作,它有利于代码的复用
2023-06-02

Android程序自动更新功能模块的实现方法【附完整demo源码下载】

本文实例讲述了Android程序自动更新功能模块的实现方法。分享给大家供大家参考,具体如下: 在程序启动的时候检测服务器上有没有对应版本更新,如果有更新,提示用户是否更新。 在程序启动的时候首先调用更新模块检测服务器上存放的版本号跟当前程序
2022-06-06

python的random模块及加权随机算法的python实现方法

random是用于生成随机数的,我们可以利用它随机生成数字或者选择字符串。 random.seed(x)改变随机数生成器的种子seed。 一般不必特别去设定seed,Python会自动选择seed。 random.random() 用
2022-06-04

Python Pandas模块实现数据的统计分析的方法

一、groupby函数 Python中的groupby函数,它主要的作用是进行数据的分组以及分组之后的组内的运算,也可以用来探索各组之间的关系,首先我们导入我们需要用到的模块import pandas as pd首先导入我们所需要用到的数据
2022-06-02

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录