• 关于python上的一个坑——reload导致模块重置


    在很多时候我们需要动态引入某个库,比如我们需要在服务端和客户端同时引入一个库,他们的文件名一致,如何在运行时对他们进行缓存呢?

    下面将举一个很有意思的例子,文件结构如下:
    在这里插入图片描述

    # testlib1/testModule
    num = 1
    
    • 1
    • 2
    # testlib2/testModule
    num = 2
    
    • 1
    • 2
    # -*- coding: utf-8 -*-
    # 此时有一个需求如下
    # 我们需要引入两个文件名相同的python文件
    # 且不能静态import 只能调用代码动态reload
    import importlib
    import os
    import sys
    
    
    # 情况1
    class loadModuleCS(object):
        """导入服务端和客户端的库"""
    
        def __init__(self):
            super(loadModuleCS, self).__init__()
            self.clientModule = None
            self.serverModule = None
            self.loadClientModule()
            self.loadServerModule()
    
        def _loadModule(self, path):
            """加载path下的模块"""
            name = os.path.basename(path)
            path = path.replace(name, "")
            sys.path.insert(0, path)
            module = importlib.import_module(name.split('.')[0])
            importlib.reload(module)
            print("库里的num为: ", module.num)
            sys.path.pop(0)
            return module
    
        def loadClientModule(self):
            path = r"F:\PythonXSLWorkSpace\PythonBaseUse\pythonBug\1error\testlib1\testModule.py"
            self.clientModule = self._loadModule(path)
    
        def loadServerModule(self):
            path = r"F:\PythonXSLWorkSpace\PythonBaseUse\pythonBug\1error\testlib2\testModule.py"
            self.serverModule = self._loadModule(path)
    
    
    loader = loadModuleCS()
    print(loader.clientModule.num)
    print(loader.serverModule.num)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    在这里插入图片描述

    思考

    运行结果如上,思考一个事情:我们在导入的时候库是正确的,那为什么我们重新将 clientModule 和 serverModule 拿出来取里面的值,却不对了?

    我们来做一个事情:

    
    loader = loadModuleCS()
    print(loader.clientModule.num)
    print(loader.serverModule.num)
    print(loader.clientModule is loader.serverModule)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    打印结果如下:

    在这里插入图片描述
    这下就一目了然了,在这个时候他们实际上同一个东西!也就是说 clientModule 和 serverModule 当前是引用到同一个对象!!why?????

    我们都知道,python导入的库都是存放在 sys.modules中, sys.modules 是一个字典,存放了导入的各个模块,会不会就是这一个原因呢?

    验证

    class loadModuleCS(object):
        """导入服务端和客户端的库"""
    
        def __init__(self):
            super(loadModuleCS, self).__init__()
            self.clientModule = None
            self.serverModule = None
            self.loadClientModule()
            self.loadServerModule()
    
        def _loadModule(self, path):
            """加载path下的模块"""
            name = os.path.basename(path)
            path = path.replace(name, "")
            sys.path.insert(0, path)
            module = importlib.import_module(name.split('.')[0])
            importlib.reload(module)
            print("库里的num为: ", module.num)
            print(sys.modules["testModule"])
            sys.path.pop(0)
            return module
    
        def loadClientModule(self):
            path = r"F:\PythonXSLWorkSpace\PythonBaseUse\pythonBug\1error\testlib1\testModule.py"
            self.clientModule = self._loadModule(path)
    
        def loadServerModule(self):
            path = r"F:\PythonXSLWorkSpace\PythonBaseUse\pythonBug\1error\testlib2\testModule.py"
            self.serverModule = self._loadModule(path)
    
    
    loader = loadModuleCS()
    print(sys.modules["testModule"])
    print(loader.clientModule.num)
    print(loader.serverModule.num)
    print(loader.clientModule is loader.serverModule)
    print(loader.clientModule is sys.modules["testModule"], loader.serverModule is sys.modules["testModule"])
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    此时输出结果如下
    在这里插入图片描述
    验证了我们的猜想,此时 clientModule 和 serverModule 当前是引用到同一个对象

    修改方案

        def _loadModule(self, path):
            """加载path下的模块"""
            name = os.path.basename(path)
            path = path.replace(name, "")
            sys.path.insert(0, path)
            moduleName = name.split('.')[0]
            if moduleName in sys.modules:
                sys.modules.pop(moduleName)
            module = importlib.import_module(moduleName)
            importlib.reload(module)
            print("库里的num为: ", module.num)
            print(sys.modules["testModule"])
            sys.path.pop(0)
            return module
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    此时就符合我们的预期了,clientModule 和 serverModule 分别引用到两个不同的库!

    在这里插入图片描述

  • 相关阅读:
    看动画,学Java基础教程12:关键字
    接口自动化测试 —— JMeter断言基本使用!
    2.1 OrCAD软件中怎么新建库文件?【OrCAD原理图封装库50问解析】
    vue-router 相关面试题
    限定input输入框输入类型(只能输入数字。。)
    数据库去除重复数据(id除外)
    Springboot+学生作业管理系统 毕业设计-附源码251208
    计讯物联智慧合杆在智慧城市中的应用
    如何用C/C++实现去除字符串头和尾指定的字符
    大一学生《Web编程基础》期末网页制作 HTML+CSS鲜花网页设计实例
  • 原文地址:https://blog.csdn.net/weixin_40301728/article/details/125337087