Python中如何同时运行多版本模块

用 python 比较多的同学可能都遇到过 python 多版本的问题,其中又包括:

  1. python 自身多版本
  2. 应用依赖包多版本

针对上面两点,目前已经有了比较成熟的解决方案,分别是 pyenv 和 virtualenv,对于本地开发或者线上部署都起到很方便的作用

但是今天正巧碰到一个需求,在一个算法托管平台上,算法同学希望能支持同一算法包多版本同时运行,方便进行灰度比较并及时更新版本
对于这种情况,pyenv 和 virtualenv 就显得心有余而力不足了
最终决定自己开发搞了一个工具包,支持同一算法包的版本隔离及卸载,重新加载,大体用法如下:

# 导入多版本模块  
lib_1 = import_module("lib", version=1)
lib_2 = import_module("lib", version=2)

模块方法调用

lib_1.show() lib_2.show()

列出此模块同时运行哪些版本

modules = list_all_version_of_module(“lib”) print(modules)

卸载模块

unload_module(“lib”, 1)

重新载入模块

lib_2 = reload_module(“lib”, 2) lib_2.show()

卸载该模块所有版本

unload_all_module(“lib”)

本地已经试验通过了,而且项目代码只有百行左右
在这里提供给大家参考,欢迎大家使用并提出建议

代码地址:vimport


Python中如何同时运行多版本模块

7 回复

用虚拟环境切分不能解决这个问题嘛?起两个进程实例对比


这个问题挺常见的,其实就是想在一个Python环境里同时用不同版本的同一个库。最直接的办法是用虚拟环境,但如果你非得在一个环境里搞,可以试试importlib

核心思路是修改模块的__name__,让Python把它们当成不同的模块来加载。下面是个具体的例子,假设你想同时用requests库的2.x和3.x版本(这里用两个不同小版本号示意):

import importlib.util
import sys

def import_module_from_path(module_name, file_path):
    """从指定路径动态导入模块,并赋予自定义的模块名"""
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    sys.modules[module_name] = module
    spec.loader.exec_module(module)
    return module

# 假设你已经把不同版本的requests库文件放在了本地
# 例如:requests_v2.py 和 requests_v3.py
# 这里用两个同目录下的示例模块文件演示
import_module_from_path('requests_v2', './requests_v2.py')
import_module_from_path('requests_v3', './requests_v3.py')

# 现在可以像使用不同模块一样使用它们
import requests_v2
import requests_v3

print(f"Version 2: {requests_v2.__version__}")
print(f"Version 3: {requests_v3.__version__}")

# 分别调用它们的功能
# resp2 = requests_v2.get('http://example.com')
# resp3 = requests_v3.get('http://example.com')

关键点:

  1. 你需要先把不同版本的库文件(比如.py文件或包目录)准备好,放在不同的路径下。
  2. import_module_from_path函数是关键,它通过importlib机制,将一个文件加载为一个指定名称的模块,并注册到sys.modules里。
  3. 之后你就可以用import requests_v2import requests_v3这样的方式,把它们当作两个完全独立的模块来用了。

更实际的场景: 如果是一个已安装的包,你可以通过pip install指定--target参数安装到不同目录,或者直接手动复制包目录。然后修改上面的file_path指向对应的__init__.py或模块文件即可。

一句话总结:importlib动态导入并重命名模块是最实用的单环境多版本共存的方案。

docker 不能解决你的需求么?还要去改代码

楼上谦虚点能死
我现在用的是 openstack 的那套模块插拔机制

楼上的没看需求就评论,点开标题前我想了想,应该是一个会话里想使用一个模块的多个版本
简单看了看源码,模块自身需要定义好版本目录结构,在协议好的环境中工作

楼主应该是说同一进程下导入不同模块

感谢大家回复,我统一解释下:
统一种问题有多种解法,需要定位用哪一种来解决更合理
1. 虚拟环境切分当然可以,那么久意味着下次用户对包稍微调整下逻辑,你就得起一个独立的环境,对于频繁发布快速迭代你怎么处理?这是个很重的运维问题
2. docker 也可以解决,但是用户还是会迭代包的,你可以统一打一个镜像,然后拉不同的包起进程,但本质仍是很重的部署问题,不但消耗资源,还强依赖调度器,又是一个运维问题

openstack 没有经验,欢迎贴出代码目录,大家一起学习下,感谢

是这样的,是在同一个进程中运行多个版本模块,这种需求需要定义一个指定目录,剩下的版本会有规范控制,对于频繁引入二方包的场景是很合适的

回到顶部