在很多时候我们需要动态引入某个库,比如我们需要在服务端和客户端同时引入一个库,他们的文件名一致,如何在运行时对他们进行缓存呢?
下面将举一个很有意思的例子,文件结构如下:
# testlib1/testModule
num = 1
# testlib2/testModule
num = 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)
思考
运行结果如上,思考一个事情:我们在导入的时候库是正确的,那为什么我们重新将 clientModule 和 serverModule 拿出来取里面的值,却不对了?
我们来做一个事情:
loader = loadModuleCS()
print(loader.clientModule.num)
print(loader.serverModule.num)
print(loader.clientModule is loader.serverModule)
打印结果如下:
这下就一目了然了,在这个时候他们实际上同一个东西!也就是说 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"])
此时输出结果如下
验证了我们的猜想,此时 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
此时就符合我们的预期了,clientModule 和 serverModule 分别引用到两个不同的库!