conda init
和 conda activate
#
conda
默认附带虚拟环境。 当您安装 Anaconda 或 Miniconda 时,您会获得一个 base
环境,它本质上是一个带有额外检查的常规环境。 这些检查与 conda
命令的实际含义以及它在您的系统中的安装方式有关。
基础前缀与目标前缀
最初,conda
的基础安装被称为root 环境。 所有其他环境都位于该 root 环境中的 envs/
下。 root 环境后来被重命名为 base,但代码仍然使用旧术语来区分 base 和 target
context.root_prefix
:base
conda 安装所在的路径。context.target_prefix
:conda
正在其上运行命令的环境。 通常默认为激活的环境,除非在命令行中指定了-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 及其对应的激活器
posix
、ash
、bash
、dash
、zsh
:均由PosixActivator
驱动。csh
、tcsh
:CshActivator
。xonsh
:XonshActivator
。cmd.exe
:CmdExeActivator
。fish
:FishActivator
。powershell
:PowerShellActivator
。
您可以通过 conda shell.<key>
命令添加所有这些类,其中 key
是上面列表中的任何名称。 这些 CLI 接口提供多个子命令,直接连接到同名的方法
activate
:编写 shell 代码以激活给定的环境。deactivate
:编写 shell 代码以停用给定的环境。hook
:编写 shell 代码以注册conda
shell 代码的初始化代码。commands
:编写自动完成引擎所需的 shell 代码。reactivate
:编写用于停用后激活的 shell 代码。
要明确的是,我们说这些函数仅编写 shell 代码。 它们不执行它! 这需要由 shell 本身完成! 这就是为什么我们需要一个 conda
shell 函数,以便可以在会话中 eval
或 source
这些 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'