conda initconda activate#

conda 默认附带虚拟环境。 当您安装 Anaconda 或 Miniconda 时,您会获得一个 base 环境,它本质上是一个带有额外检查的常规环境。 这些检查与 conda 命令的实际含义以及它在您的系统中的安装方式有关。

基础前缀与目标前缀

最初,conda 的基础安装被称为root 环境。 所有其他环境都位于该 root 环境中的 envs/ 下。 root 环境后来被重命名为 base,但代码仍然使用旧术语来区分 base 和 target

  • context.root_prefixbase conda 安装所在的路径。

  • context.target_prefixconda 正在其上运行命令的环境。 通常默认为激活的环境,除非在命令行中指定了 -n(名称)或 -p(前缀)。 请注意,如果您正在 base 环境中操作,则目标前缀将与根前缀具有相同的值。

当您在终端中键入 conda 时,您的 shell 将尝试查找以下内容之一

  • 名为 conda 的 shell 函数

  • 您的 PATH 目录中名为 conda 的可执行文件

如果您的 conda 安装已正确初始化,它将找到 shell 函数。 如果没有,如果 conda 可执行文件碰巧PATH 中,它可能会找到它,但这种情况通常不会发生。 这就是为什么一开始就需要初始化!

Conda 初始化#

为什么一开始就需要初始化? 有几个原因

  • 激活需要与 shell 上下文非常紧密地交互

  • 它不会不必要地污染 PATH

  • 提高某些操作的性能

初始化的主要思想是提供一个 conda shell 函数,该函数允许 Python 代码更深入地与 shell 上下文交互。 它还允许更简洁的 PATH 操作和在某些 conda 命令中更快的响应。

conda shell 函数主要是一个 转发器函数。 它会将大多数命令委托给由 Python 库驱动的真实 conda 可执行文件。 但是,它会拦截两个非常特定的子命令

  • conda activate

  • conda deactivate

需要进行此拦截,因为激活/停用需要将环境变量导出(或取消设置)回 shell 会话(而不仅仅是临时在 Python 进程中)。 这将在下一节中讨论。

那么如何执行初始化呢? 这是 conda init 子命令的工作,由 conda.cli.main_init 模块驱动,该模块直接依赖于 conda.core.initialize 模块。 让我们看看这是如何实现的。

conda init 将通过在 shell 的相关启动脚本(例如 ~/.bashrc)中编写一些 shell 代码来永久初始化 shell。 这是通过 conda.core.initialize 中定义的各种函数完成的,即

  • init_sh_user:为当前用户初始化 Posix shell(如 Bash)。

  • init_sh_system:全局初始化 Posix shell(如 Bash),适用于所有用户。

  • init_fish_user:为当前用户初始化 Fish shell。

  • init_xonsh_user:为当前用户初始化 Xonsh shell。

  • init_cmd_exe_registry:通过 Windows 注册表初始化 Cmd.exe。

  • init_powershell_user:为当前用户初始化 Powershell。

  • init_long_path:配置 Windows 以支持更长的路径。

每个函数的作用取决于每个 shell 的性质。 对于 Bash shell,底层的 Activator 子类(稍后会详细介绍)可以动态生成 hook 代码。 在其他 Posix shell 和 Powershell 中,脚本从其在 base 环境中的位置获取。 对于 Cmd,更改通过 Windows 注册表引入。 最终结果是相同的:它们最终将定义一个 conda shell 函数,其行为如上所述。

Conda activate#

所有 Activator 类都可以在 conda.activate 下找到。 它们的工作本质上是以编程方式编写 shell 原生代码。 截至 conda 4.11,这些是受支持的 shell 及其对应的激活器

  • posixashbashdashzsh:均由 PosixActivator 驱动。

  • cshtcshCshActivator

  • xonshXonshActivator

  • cmd.exeCmdExeActivator

  • fishFishActivator

  • powershellPowerShellActivator

您可以通过 conda shell.<key> 命令添加所有这些类,其中 key 是上面列表中的任何名称。 这些 CLI 接口提供多个子命令,直接连接到同名的方法

  • activate:编写 shell 代码以激活给定的环境。

  • deactivate:编写 shell 代码以停用给定的环境。

  • hook:编写 shell 代码以注册 conda shell 代码的初始化代码。

  • commands:编写自动完成引擎所需的 shell 代码。

  • reactivate:编写用于停用后激活的 shell 代码。

要明确的是,我们说这些函数仅编写 shell 代码。 它们执行它! 这需要由 shell 本身完成! 这就是为什么我们需要一个 conda shell 函数,以便可以在会话中 evalsource 这些 shell 字符串。

让我们看看当您运行 conda shell.bash activate 时会发生什么

$ conda shell.bash activate
export PATH='/Users/username/.local/anaconda/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/username/.local/anaconda/condabin:/opt/homebrew/bin:/opt/homebrew/sbin'
unset CONDA_PREFIX_1
PS1='(base) '
export CONDA_PREFIX='/Users/username/.local/anaconda'
export CONDA_SHLVL='1'
export CONDA_DEFAULT_ENV='base'
export CONDA_PROMPT_MODIFIER='(base) '
export CONDA_EXE='/Users/username/.local/anaconda/bin/conda'
export _CE_M=''
export _CE_CONDA=''
export CONDA_PYTHON_EXE='/Users/username/.local/anaconda/bin/python'

看到了吗? 它只将一些 shell 代码写入了 stdout,但它没有执行。 我们需要这样做才能实际运行它

$ eval "$(conda shell.bash activate)"

这基本上就是 conda activate 所做的事情:它调用注册的 shell 激活器以获取所需的 shell 代码,然后 eval 它。 在某些没有 eval 等效项的 shell 中,会编写一个临时脚本并进行 source 或调用。 最终效果是相同的。

好的,但是 shell 代码在做什么? 主要是正确设置您的 PATH,以便可以找到您的 base 环境的可执行文件(如 python)。 它还设置了一些额外的变量,以保留对当前激活环境的路径、shell 提示符修饰符以及 conda 内部的其他信息的引用。

此命令还可以为任何其他您想要的环境生成代码,而不仅仅是 base。 只需传递名称或路径

$ conda shell.bash activate mamba-poc
PS1='(mamba-poc) '
export PATH='/Users/username/.local/anaconda/envs/mamba-poc/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/username/.local/anaconda/condabin:/opt/homebrew/bin:/opt/homebrew/sbin'
export CONDA_PREFIX='/Users/username/.local/anaconda/envs/mamba-poc'
export CONDA_SHLVL='2'
export CONDA_DEFAULT_ENV='mamba-poc'
export CONDA_PROMPT_MODIFIER='(mamba-poc) '
export CONDA_EXE='/Users/username/.local/anaconda/bin/conda'
export _CE_M=''
export _CE_CONDA=''
export CONDA_PYTHON_EXE='/Users/username/.local/anaconda/bin/python'
export CONDA_PREFIX_1='/Users/username/.local/anaconda'

现在路径不同了,以及一些数字(例如 CONDA_SHLVL)。 conda 使用它来跟踪之前激活的内容,因此当您停用最后一个时,您可以无缝地返回到上一个。

激活/停用脚本#

激活/停用代码还可以包括对激活/停用脚本的调用。 如果它们存在于 shell 的相应目录中(例如 CONDA_PREFIX/etc/conda/activate.d/),它们将在停用之前或激活之后分别被调用。 例如,编译器通常设置一些环境变量以帮助配置默认标志。 这就是当您激活包含 Clang 和 Gfortran 的环境时发生的情况

$ conda shell.bash activate compilers
PS1='(compilers) '
export PATH='/Users/username/.local/anaconda/envs/compilers/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/username/.local/anaconda/condabin:/opt/homebrew/bin:/opt/homebrew/sbin'
export CONDA_PREFIX='/Users/username/.local/anaconda/envs/compilers'
export CONDA_SHLVL='2'
export CONDA_DEFAULT_ENV='compilers'
export CONDA_PROMPT_MODIFIER='(compilers) '
export CONDA_EXE='/Users/username/.local/anaconda/bin/conda'
export _CE_M=''
export _CE_CONDA=''
export CONDA_PYTHON_EXE='/Users/username/.local/anaconda/bin/python'
export CONDA_PREFIX_1='/Users/username/.local/anaconda'
. "/Users/username/.local/anaconda/envs/compilers/etc/conda/activate.d/activate-gfortran_osx-arm64.sh"
. "/Users/username/.local/anaconda/envs/compilers/etc/conda/activate.d/activate_clang_osx-arm64.sh"
. "/Users/username/.local/anaconda/envs/compilers/etc/conda/activate.d/activate_clangxx_osx-arm64.sh"

这三行正在获取相关脚本。 同样,对于停用,请注意这次停用脚本是如何首先执行的

$ conda shell.bash deactivate
export PATH='/Users/username/.local/anaconda/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/username/.local/anaconda/condabin:/opt/homebrew/bin:/opt/homebrew/sbin'
. "/Users/username/.local/anaconda/envs/compilers/etc/conda/deactivate.d/deactivate_clangxx_osx-arm64.sh"
. "/Users/username/.local/anaconda/envs/compilers/etc/conda/deactivate.d/deactivate_clang_osx-arm64.sh"
. "/Users/username/.local/anaconda/envs/compilers/etc/conda/deactivate.d/deactivate-gfortran_osx-arm64.sh"
unset CONDA_PREFIX_1
PS1='(base) '
export CONDA_PREFIX='/Users/username/.local/anaconda'
export CONDA_SHLVL='1'
export CONDA_DEFAULT_ENV='base'
export CONDA_PROMPT_MODIFIER='(base) '
export CONDA_EXE='/Users/username/.local/anaconda/bin/conda'
export _CE_M=''
export _CE_CONDA=''
export CONDA_PYTHON_EXE='/Users/username/.local/anaconda/bin/python'