conda环境可以继承基本软件包吗?

时间:2019-03-18 13:22:31

标签: python conda

我正在寻找环境 do 从根继承的解决方案,但是寻找答案似乎有很多困惑。许多OP问题认为,它们不是在继承程序包。因此,搜索结果找到了这些问题,但是答案却有相反的解决方案(或只是解释说错了)。

也就是说,一个OP实际上具有相似的目标。 Can packages be shared across Anaconda environments?该OP表示他们的HDD空间不足。暗示“共享”应该在新环境中使用相同的已安装软件包。答案(不接受)是使用--clone

我还发现了这篇帖子Do newly created conda envs inherit all packages from the base env?,其中说--clone不共享软件包。 OP在这篇文章中认为他们的新环境是“共享”程序包,然后得出结论“共享”程序包不存在。 What is the use of non-separated anaconda environments?

我测试了--clone标志和"build identical environments"选项的Conda Docs指令。两个环境目录具有相同的大小:2G +。

(base) $ conda list --explicit > spec-file.txt
# Produced Size On Disk: 2.14 GB (2,305,961,984 bytes)

(base) conda create --name myclone --clone root
# Produced Size On Disk, clone: 2.14 GB (2,304,331,776 bytes)

唯一的区别是在相同的环境中构建,再次下载了软件包,然后克隆复制了本地文件,而花费的时间更少了。。

我使用Miniconda将CLI工具部署到同事工作站。基本上,当我需要添加基本安装中不需要的特定模块时,所有工具都使用相同的软件包,但偶尔会例外。

目标是将conda create用于扩展virtualenv --system-site-packages类似的基本软件包的环境,并且不重复安装。

1 个答案:

答案 0 :(得分:1)

Conda环境是否应该继承基本软件包?

否。建议的工作流程是使用conda create --clone创建一个新的独立环境,然后对该环境进行更改以添加其他软件包。或者,可以将模板环境转储到YAML(conda env export > env.yaml),对其进行编辑以包括或删除软件包,然后从中创建一个新环境(conda env create -f env.yaml -n foo)。

在大多数情况下,对这种浪费存储的担心是没有根据的。 1 由于Conda的使用,可能会有许多新环境比实际占用的空间更大。硬链接以最大程度地减少冗余。在问题Why are packages installed rather than just linked to a specific environment?中可以找到对此的更详细的分析。

Conda环境可以继承基本软件包吗?

不支持,但是有可能。首先,让我们明确声明通过conda activate --stack命令的nested activation of Conda environments无法启用或帮助允许跨环境继承Python包。这是因为它不操纵PYTHONPATH,而是仅将先前的活动环境保留在PATH上,并跳过停用的脚本。 this GitHub Issue中对此有更详细的讨论。

现在,我们避免了红色鲱鱼,让我们谈谈PYTHONPATH。可以使用此环境变量来包含其他site-packages目录进行搜索。所以,天真地像

conda activate foo
PYTHONPATH=$CONDA_ROOT/lib/python3.7/site-packages python

应使用可用的 base foo 软件包启动Python。起作用的一个关键约束是,新环境中的Python必须与 base 的版本匹配,直到次要版本(在本例中为3.7。*)为止。

仔细研究细节

虽然这将实现包继承,但我们需要考虑:这实际上会节省空间吗?我认为在实践中可能不会,并且为什么。

大概我们不想在物理上复制Python安装,但是新环境必须安装Python,以帮助限制对所需新软件包的求解。为此,我们不仅应该匹配Python版本(conda create -n foo python=3.7),而且应该与 base 完全相同的内部版本:

# first check base's python
conda list -n base '^python$'
# EXAMPLE RESULT
# Name                    Version                   Build  Channel
python                    3.7.6                h359304d_2 

# use this when creating the environment
conda create -n foo python=3.7.6=h359304d_2

这将使Conda进行链接,并在两种环境中使用相同的物理副本。但是,不能保证Python的依赖项也会重用 base 中的软件包。实际上,如果有兼容的较新版本可用,它将下载并安装这些版本。

此外,假设我们现在安装了scikit-learn

conda install -n foo scikit-learn

这将再次检查它的最新版本及其依赖项,而与这些依赖关系的较旧但兼容的版本是否已经可以通过 base 获得。因此,不必要将更多软件包安装到软件包缓存中。

这里的模式似乎是我们真的想找到一种方法来使 foo env安装新软件包,但要使用尽可能多的现有软件包来满足依赖性。这正是conda create --clone已经做的。 2

因此,我完全失去了继承的动力。


注意

我推测,对于纯Python软件包的特殊情况,可以使用 base 环境中的pip install --target安装与 base 兼容的软件包>到 base 之外的位置。然后,用户可以从 base 启动PYTHONPATH之前将此目录添加到python

这不是我的首选。我知道克隆策略是可以控制的;我不知道从长期来看会发生什么。


[1] 这将一直存在,只要程序包缓存(pkgs_dirs)的位置以及创建环境的位置(默认为envs_dirs )的音量相同。具有多个卷should be using softlinks的配置,最终将具有相同的效果。除非有人手动禁用这两种类型的链接,否则Conda会在静默减少冗余方面做得不错。

[2] 从技术上讲,使用--offline标志来强制Conda使用已经缓存的内容也可能会有所刺痛。但是,OP的前提是附加软件包是新软件包,因此假设我们在缓存中已经具有兼容版本可能是不明智的。