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

    在这里插入图片描述

  • 相关阅读:
    ES6中set的基础、map数据结构和DOM classList的基础用法
    教给孩子们如何认真听讲
    Pytorch学习——梯度下降和反向传播 03 未完
    数据结构--栈
    微信小程序--》小程序—自定义组件使用
    C Primer Plus(6) 中文版 第7章 C控制语句:分支和跳转 7.1 if语句
    JavaScript设计模式(三)——单例模式、装饰器模式、适配器模式
    【第37篇】EdgeViTs: 在移动设备上使用Vision Transformers 的轻量级 CNN
    P1039 [NOIP2003 提高组] 侦探推理
    使用Python,Xpath获取所有的漫画章节路径,并下载漫画图片生成单个/多个pdf,并进行pdf合并
  • 原文地址:https://blog.csdn.net/weixin_40301728/article/details/125337087