pip安装的两个模块同名,如何选择加载哪一个?

wil*_*lks 4 python pip python-module pypi

我正在编写一个依赖于特定模块的python程序rtmidi, . 事实是,PyPI 中至少有两个不同的包有一个具有该名称的模块:rtmidipython-rtmidi。它们提供几乎相同的功能,但具有不同的语法。

当仅安装“正确”的软件包时,一切正常。但是,如果安装了这两个软件包,则使用import rtmidi会加载“错误”的模块,并且我的程序会崩溃。让它再次工作的唯一方法是卸载这两个软件包,然后重新安装正确的软件包。当然,由于用户可能依赖其他模块来执行其他程序,因此我不能指望他们这样做。

尝试识别模块会rtmidi.__name__给出与两个包相同的结果。

所以我的问题是,我该如何解决这个名称冲突问题?有没有最佳实践方法来处理这个问题?

小智 5

您不能同时安装它们(如果依赖默认pip行为)。在这里,我将使用几个存在导入名称冲突的简单纯 Python 包进行演示:coverallspython-coveralls

# in a fresh environment
pip install python-coveralls
python -c "import coveralls; print(dir(coveralls)); print(coveralls.__file__)"
# ['__author__', '__builtins__', '__cached__', '__classifiers__', '__copyright__', 
# '__doc__', '__docformat__', '__file__', '__license__', '__loader__', '__name__', 
# '__package__', '__path__', '__spec__', '__version__', 'parse_args', 'wear']
# /path/to/lib/python3.8/site-packages/coveralls/__init__.py
Run Code Online (Sandbox Code Playgroud)

这些是 的内容python-coveralls。请注意,实际__init__.py文件位于该site-packages/coveralls/目录中。

pip install coveralls
python -c "import coveralls; print(dir(coveralls)); print(coveralls.__file__)"
# ['Coveralls', '__all__', '__builtins__', '__cached__', '__doc__', '__file__', 
# '__loader__', '__name__', '__package__', '__path__', '__spec__', '__version__', 
# 'api', 'exception', 'git', 'reporter', 'version']
# /path/to/lib/python3.8/site-packages/coveralls/__init__.py
Run Code Online (Sandbox Code Playgroud)

这些是 的内容coverallspython-coveralls已被覆盖。请注意,这是同一个文件。旧的一切都__init__.py消失了。

pip uninstall coveralls
python -c "import coveralls; print(dir(coveralls)); print(coveralls.__file__)"
# ['__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', 
# '__spec__']
# None
Run Code Online (Sandbox Code Playgroud)

那里仍然有一个包的影子,但它的内容已经消失了(除了所有包内部都有的东西)。请注意,该文件现在是:该包None没有文件。__init__.py

pip uninstall python-coveralls您还可以通过运行然后重新安装您想要的任何一个来取消环境。

解决方案

确实必须要求您的用户仅使用您要求的包,但这就是我们使用虚拟环境的原因。或者,想要直接使用其他包的用户可以更改安装位置(以及加载时使用的名称),并选择--targetpip但这不会帮助使用其他库的其他应用程序)。

实际上,最好将其视为安装过程的一部分。您需要 (a) 告诉您的用户他们需要安装哪些要求;(b) 拥有一些满足正确要求的自动化流程。

我想说最佳实践是(b)。执行此操作的常见方法是使用setuptools, 并定义函数install_requires的参数setup。这是指 PyPI 上的包名称,而不是导入名称。setuptools 快速入门是一个很好的起点。