我可以在全局或另一个虚拟环境中导入安装在一个虚拟环境中的包吗?

Can I import a package installed in one virtual environment in global or another virtual environment?

我想在我的电脑上安装两个版本的 TensorFlow (tf)。我的一些程序 运行 在 tf v1 上,一些在 tf v2 上。因此,我可以单独创建两个虚拟环境 (venv),一个用于 tf v1,另一个用于 tf v2,并为每个 venv 使用 --use-system-packages 以满足我的代码的其他(全局)包要求。然后,我会将我的程序保存在安装了正确 tf 版本的相应 venv 中。

但是,出于某些特定原因,我也希望能够在全局环境中使用两个版本的 TensorFlow(即无需输入/激活 venv)。

问题:

有没有一种方法可以让我在 2 个 venvs 中安装 2 个版本的 TensorFlow (and/or numpy),然后使用 import 语句(版本 / venv 从指定导入)?如果使用 venvs 无法做到这一点,是否有其他方法可以实现同样的目标?

进一步扩展,假设我在 venv 中。我想知道我是否可以导入安装在其他一些 venv 中的包?如果是,如何?

问题定义: 我们需要导入两个不同版本的 Python 包。两个版本都有依赖关系并提供相同的命名空间 (tensorflow)。

为什么不可能:当Python加载模块(import tensorflow as tf)时,它试图避免冗余工作并跳过已加载的模块已经。 因此,不可能从两个不同的位置加载相同的命名空间。

一些有趣的事实:

  • 您可以操纵 Python 将在运行时查找模块的路径。第一次加载模块时,Python 将遍历 sys.path 中的目录列表,寻找请求的命名空间。 sys.path 中的目录依赖于安装,但通常按以下顺序排列:本地目录、内置模块、已安装的包。最后一个是一个目录或一组目录,您的包管理器(pip,easy_install,...)存储已安装的包。它通常不止一个位置,包括系统范围内安装的包、用户文件夹(例如 ~/.local/lib/pythonX.Y/site-packages)和特定于虚拟环境的文件夹(例如 xxx.venv/lib/pythonX.Y/site-packages)。根据设置,您可以使用这些的任意组合。有趣的是您可以插入新目录:sys.path[6:6] = ['path/to/another/venv/lib/pythonX.Y/site-packages']。但是,由于缓存的原因,它无助于获取同一命名空间的两个实例。
  • sys.path 个文件夹中,Python 将查找具有匹配名称的模块,它代表一个命名空间。 Python 包名通常与它们提供的命名空间相同,但也可以不同。例如,在 pip install numpy 中,最后一部分是包名称,但在 import numpy 中,它是一个命名空间。所有 PyPI 包的命名空间中大约有 1/3 与包名称不同,例如包 intel-numpy 也提供了命名空间 numpy。如果您安装 intel-numpy,pip 将静默覆盖之前由 numpy 提供的文件夹(以及命名空间的内容)。是的,Python 包管理器跟踪已安装的包名称,但不跟踪命名空间。因此,即使一个包的两个版本提供了不同的命名空间,您也不能同时拥有它们。但是如果你有两个不同的包提供相同的命名空间,pip 会很乐意安装两个,但只会保留最后安装的。
  • 如果同一个包的两个版本提供不同的命名空间,您可以为它们安装不同的虚拟环境,然后操作sys.path以包含来自两个版本的包并同时获取两个命名空间。不过我们不是这样。
  • 另一种选择:重新打包一个版本的包,重命名命名空间。在这种情况下,更改包名称并将它们安装在相同的 place/venv 中会更容易。您甚至可以将这个重新打包的包版本重新上传到 PyPI(我见过有人这样做),但由于依赖版本的差异,它不适用于 TF 和任何其他非平凡的包。有趣的事实:Python 包管理器不解析依赖版本;如果包 A 需要 C==1.0,B 需要 C==2.0,安装 A 和 B 后,您将只有一个版本的 C,导致 A 或 B 瘫痪。

最后,为什么不应该这样做:这违反了 Python 原则。显式优于隐式,在运行时操作库路径并不是最透明和最受支持的方法。尽管如此,维护一组兼容的依赖项的问题仍然存在,这就是我们拥有 venv、pipenv 等的原因。

从语言设计的角度来看,处理同一个包的多个版本确实有其好处,并被多种语言(如 JS)采用。但是,它使进口产品变得更加昂贵。从历史上看,这是 Python 社区的小众场景,因此它不会超过性能损失。