conda initconda activate#

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

基本前缀与目标前缀

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

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

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

当您在终端中键入 conda 时,您的 shell 会尝试找到:

  • 一个名为 conda 的 shell 函数

  • 一个名为 conda 的可执行文件,位于您的 PATH 目录中

如果您的 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 子类(下面将详细介绍)可以动态生成钩子代码。在其他 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 函数,以便这些 shell 字符串可以在会话中被 evalsource

$ 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'

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

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

看到了吗?它只将一些 shell 代码写入标准输出,但没有执行。我们需要这样做才能真正运行它。

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

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

$ 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'

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

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

激活/停用脚本#

$ 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"

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

$ 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'