• 关于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 分别引用到两个不同的库!

    在这里插入图片描述

  • 相关阅读:
    Terraform基础入门 (Infrastructure as Code)
    【Vue】使用 transition 标签实现单元素组件的过渡和动画效果(1)
    战略篇-EMC三板斧
    c# xml 参数配置表的使用
    【前端】WebWorker 在前端SPA框架的应用
    disruptor (史上最全之1):伪共享原理&性能对比实战
    MongoDB中 $type 字段、索引、聚合的概念以及相应操作命令
    Open3D-读取深度图
    【NLP】AI相关比赛汇总(2022)
    批量处理实验接触角数据-MATLAB分析
  • 原文地址:https://blog.csdn.net/weixin_40301728/article/details/125337087