Python 虚拟环境
- Published on
补丁补丁又补丁,几番周折后,现在觉得撇开 pyenv
,单独安装使用 conda
也挺好。如果 P 能始终无痛且完整同步地管着 C,当然是最有序的;但如果出现冲突或 P 的管束会影响限制 C 的发挥使用,那还不如解绑各自独立,虽然关系上感觉会混乱些,但我系统内的混乱多了去了,硬让它俩干净有序又如何。当下还先继续这样用,即 pyenv
全都统一管着,后面如果又有问题再说,真不行就重新独立安装 conda
,克隆当前环境。(1222 补)
目录
啰嗦预警
这篇博客的原始版本还没有发布,因为我换了工具,于是加了一个 啰嗦补丁
(已被 啰嗦预警
替代),结果沿着那个思路还没有重新整理完,又有了惊人的新发现,二次反转来了,于是就补丁落补丁,有了这个 啰嗦预警
。
核心问题就是,使用什么工具创建、管理 Python 的虚拟环境?
Python 本身其实自带 venv
模块可以用来创建虚拟环境,但是一方面它的功能可能相对基础,另一方面这个 Python 是什么 Python,版本是多少?在一个操作系统中,根据不同的项目需求,也为了不污染影响系统本身的 Python 环境,肯定还是要另外安装使用其它 Python 。其它这些 Python 用什么工具安装管理,如何基于它们创建虚拟环境,如何管理虚拟环境中安装的各种新的依赖。只靠 venv
显然是不能解决这些问题的,还需要其他工具。
我最开始使用 Python 做项目的时候,当时选用的就是 pyenv
,那时的背景和考量如下:
当时重点参照了 real-python
上这篇介绍 pyenv
的教程:
所以很自然地,如今也还是继续用它,这篇文章的初始版本也是在这样的背景下写的,工具的选择没有变,只是对它们解决的问题有了更深入的理解。
如下图所示,我又用 pyenv
安装了一个新的 Python 3.12.0,并用 pyenv-virtualenv
插件基于这个 Python 创建了新的虚拟环境,并在其中安装 JupyterLab
。
因为 JupyterLab
的依赖很多,而且过程中出了点问题,我又看了其他一些资料,为了克服 pip
通过生成 requirements.txt
管理依赖的漏洞问题,就决定换用 conda
。
这是第一次转折。
参照着 Miniconda 的官方安装指南,我卸载了 Python 3.12.0,安装了 conda
,并用它创建了虚拟环境 base_py
。
由此,我以为自己从 pyenv
切换到了 conda
。
结果,就在我根据这次转变重新整理这篇博客的时候,无意中瞄到 pyenv-virtualenv
主页使用说明上说它们也可以安装管理 conda
环境。我就非常震惊,怎么会这样,之前怎么没看到,我以为自己跟它倆说拜拜了,结果它们让我站住并回来...
这是第二次转折。
我当然要卸掉刚独立安装的 miniconda
再用 pyenv
重新安装一次。虽然麻烦,但是如此一来,整个操作系统内所有的 Python 环境全都可以交给 pyenv
统一安装管理,对此我感到非常好受。相比之下,重复安装那点麻烦不算什么,我要它们整整齐齐的。
于是,虽然标题是关于 Python 的虚拟环境,到头来,整篇文章感觉就是在夸 pyenv
大法好。
我不觉得自己的反应是小题大作,我的惊讶有着充分的理由...
首先,conda
对虚拟环境的创建管理和 virtualenv
或基于它的其它工具不同。每一个 conda
虚拟环境中都装有一个 完整 的 Python。
另外,conda
可以替代 pip
安装 Python 甚至其他语言的包,相比 pyenv
、poetry
、pipenv
这些 p
打头的 Python 工具,之前总感觉它有一个自己的生态,两方阵营是择其一使用的关系。特别是在研究 conda
时,看到了 这篇博客 。其中讲到 conda
是从 Python 数据/科学 Python(PyData/SciPy) 生态中产生的,这个生态与纯 Python 开发生态还是有区别的,作者通过厘清围绕 conda
的迷思与误解,异常清晰地对这两条线的关系做了梳理和解释。例如,数据科学中常用的 NumPy
包可能包含 Python 外的其他依赖,并不是纯 Python 开发的,这就超出了 pip
的依赖管理范畴和能力,用 conda
安装会更好。具体见文中 迷思 4:开发 Conda 是不负责任的分裂 Python 的行为吗?
因为以上这些 context,当我发现 pyenv
同样可以安装管理 conda
时,才会有转折再转折的惊讶。
其实实现原理并不复杂,因为 pyenv
只是帮忙下载并运行 miniconda
的安装脚本,将其存放路径统一在自己的 Python 路径管理下。但它就是把一件事以简单的方式做得非常完备,我很喜欢。
下面其实才是原本的正文内容,参照 Python Virtual Environments: A Primer 这篇教程理解 Python 的虚拟环境,梳理 pyenv
以及 pyenv-virtualenv
的基本原理和使用方法,最后再补上 conda
的基本使用方法。
为什么需要创建和使用虚拟环境?
因为 Python 的依赖管理不好,pip
会把所有外部依赖全都默认安装在操作系统自带的 Python(后面都简称为 系统 Python
)的 site-packages
中。
可能的影响:
系统污染
因为 Linux 系统自带预装 Python,用户后来安装的外部依赖有可能会干扰操作系统本身的功能和运行
操作系统更新时,也有可能抹除或覆盖用户自己安装的依赖包
依赖冲突
- 不同的项目可能需要不同版本的同一外部依赖,如果都安装在同一个位置,自然无法同时安装两个不同的版本
项目的可复现性(reproducibility)
- 如果依赖全都安在同一个位置,就很难把某一个项目所需的依赖清晰择出作为整体独立环境分享出去
缺少安装依赖的系统管理员权限
- 不如使用自己的普通用户权限创建独立使用的虚拟环境
虚拟环境是什么?
Python 虚拟环境实质就是一个自包含的文件夹结构(folder structure),内含创建该虚拟环境的那个 Python (后面简称 基础 Python
)的可执行文件的副本或 symlinks,最核心的构成包括:
Python binary:如 Python 解释器、pip 及它们各自的 symlinks 等
pyvenv.cfg 文件:含有一些键值対,用来在
sys
模块中设置变量,决定使用哪个 Python 解释器以及site-packages
路径site-packages 路径:自带的(默认
pip
和setuptools
(pip 的依赖))以及该虚拟环境后续安装的各种外部依赖
注:Python 的标准库(standard library)并没有出现在虚拟环境中,这部分是直接复用安装该虚拟环境的 基础 Python
,这也是为什么虚拟环境更轻量、以及适合根据需求速建速删。
经设置,基础 Python
的 site-packages
也可以开放给虚拟环境使用,但是是单向性的,虚拟环境安装的外部依赖仍然是和 基础 Python
的 site-packages
严格分离的。
虚拟环境如何工作?
复制
基础 Python
的构成结构与文件修改前缀查找过程
不同于
基础 Python
,虚拟环境中的 Python 解释器不去寻找os
模块来确定标准库的位置,而是先搜索pyvenv.cfg
文件。如果这个文件中存有home
键,就会用它来设定两个变量的值:sys.prefix
指向含有pyvenv.cfg
文件的路径(即虚拟环境对应路径)sys.base_prefix
对应创建该虚拟环境的基础 Python
可执行文件所在路径
(
3.8.7
是我先用 pyenv 安装的基础 Python
,然后又使用pyenv-virtualenv
插件,通过这个基础 Python
构建了虚拟环境BeatsTracking
。)于是,标准库相关的文件会以
sys.base_prefix
为准去基础 Python
对应路径寻找;而site-packages
路径则以sys.prefix
为准在虚拟环境中查找。
链接回
标准库
前面其实已提及,虚拟环境的设计就是尽可能轻量,所以只复制最少的必要文件,即
二进制
可执行文件的副本或 symlink、pyvenv.cfg
文件和site-packages
路径。虚拟环境中的 Python 解释器可以访问标准库内的模块,通过pyvenv.cfg
文件中指定的home
路径:(
home
路径指向了创建BeatsTracking
虚拟环境的基础 Python
的可执行文件;当前第二行表示基础 Python
安装的软件 (site-packages
)不对虚拟环境解释器开放使用;如果第二行设为True
,那么下一张图中的sys.path
中就会出现基础 Python
的site-packages
的对应路径)通过添加相关路径到
sys.path
中,Python 解释器可以找到需要的文件,编程时才能被顺利导入(import
)。初始化启动时,通过自动导入site
模块,为sys.path
设置默认值。(虚拟环境中的 Python 解释器可以访问以上所有路径查找文件,包括第二行创建该虚拟环境的
基础 Python
的标准库)
修改
PYTHONPATH
- 如上图所示,虚拟环境中
sys.path
最后两行的site-packages
用虚拟环境另建的新路径替换了基础 Python
的site-packages
路径,所以实现了独立隔离项目依赖的效果。
- 如上图所示,虚拟环境中
修改 Shell
PATH
环境变量- 激活虚拟环境,其实是运行一个 Shell 脚本,把该环境对应的可执行文件路径放在系统环境变量
PATH
的最前方,于是会被操作系统优先调用。退出虚拟环境,则是运行deactivate
脚本,使系统设置恢复如初。pyenv
的工作原理也是基于此,通过把它的shims
路径放在PATH
变量的最前面,来统一管理安装的各版本 Python 调用。
- 激活虚拟环境,其实是运行一个 Shell 脚本,把该环境对应的可执行文件路径放在系统环境变量
使用绝对路径直接运行
- 不是非要激活虚拟环境才能使用它,可以直接在 Shell 中输入虚拟环境 Python 的二进制文件所在的绝对路径运行使用它。(
pyenv
也是将所有通过它安装的 Python 有规律地放在它所管理的路径下,可在系统任意路径下通过输入对应的pyenv
命令调用需要的版本,当然也可以输入绝对路径调用。)
- 不是非要激活虚拟环境才能使用它,可以直接在 Shell 中输入虚拟环境 Python 的二进制文件所在的绝对路径运行使用它。(
个性化
- 如果使用 Python 自带的
venv
,当重建一个同名虚拟环境时,它并不会删除或完全覆盖原来那个同名虚拟环境已安装的外部依赖,再次重建时,需要在命令后面加上--clear
才会删除原同名环境的数据
- 如果使用 Python 自带的
虚拟环境管理
决定虚拟环境文件夹的存放位置
使用
venv
,可以把虚拟环境与项目源码统一放在一个路径下,也可以分开把所有的虚拟环境集中一起存放管理。使用pyenv
,默认是把所有的虚拟环境统一安装在pyenv
管理的路径下,和对应项目的源码是分离存放的。除此之外,如果使用 IDE,如 VS Code 或 PyCharm,平台可能有它自己构建虚拟环境的路径与方法。虚拟环境应该是用完即弃的(disposable),除
pip
安装的依赖外,不要手动往里面添加其他东西,也不要把它纳入版本控制使用
requirements.txt
文件实现虚拟环境的可复现性#生成当前虚拟环境下已安装的所有依赖清单 python -m pip freeze > requirements.txt #安装依赖清单中的所有软件 python -m pip install -r requirements.txt
可以把这个文件纳入版本控制,和项目源码一起 ship。但是仍然有漏洞,因为构建虚拟环境的
基础 Python
版本信息是缺失的,此外还可能出现因为sub-dependency
不一致的问题导致的环境复现错误。解决方案有:使用
pip-tools
生成requirements.txt
使用
Pipenv
生成Pipfile.lock
使用
Poetry
生成poetry.lock
补充:以上
p
打头的第三方纯 Python 依赖管理工具都是为了更好地解决pip
的不足,即不够 fully deterministic。除了此处说的sub-dependency
(依赖的依赖) 问题,以及最开始啰嗦预警
提到的非纯 Python 包的依赖管理问题,还有就是,通过python setup.py install
安装的依赖,pip
也管不了。不要将虚拟环境文件夹 push 到 GitHub 仓库,不要纳入 CI/CD 流水线,不要复制到部署服务器上。通常远程服务就是以隔离的虚拟环境形式提供的,只需要根据
requirements.txt
文件安装所有需要的依赖即可。其他相关工具
以上内容主要是基于 Python 官方自带的 venv
模块,此外常用的还有 conda
以及 virtualenv
。Conda
功能更多,如不仅支持 Python,还支持其他编程语言。因为我自己用的是 pyenv
以及它基于 virtualenv
的插件 pyenv-virtualenv
,所以此处不考虑 Conda。
virtualenv
Virtualenv 是 venv
的超集,而且它实际比 venv
更早出现。
相比 venv
的优势:
创建虚拟环境的速度更快
提供最新的
pip
和setuptools
,无需创建完成后再更新支持 Python 2.x
pyenv - Python 版本管理
功能与特点
支持各个用户(per-user)设置各自的系统全局 Python 版本
支持为每个项目(per-project)提供各自对应的 Python 版本
不依赖 Python 本身,
.pyenv
是纯 Shell 脚本
工作原理
Shims
通过在 PATH
环境变量中加入 Shims
路径拦截所有 Python 包括 pip
命令,然后传递给 pyenv
,进而匹配到各软件应用对应的 Python 安装版本。例如,如果在命令行中输入 pip
:
操作系统会去
PATH
中寻找叫作pip
的可执行文件然后找到叫作
pip
的 pyenvshim
(因为在PATH
中排在最前面)于是系统运行叫作
pip
的 shim,实际则是把命令传递给了pyenv
Python 版本选择
pyenv
选择某 Python 版本的顺序:
当前工作 Shell 对应的版本,可由
pyenv shell
命令通过设定PYENV_VERSION
环境变量设定某应用软件具体对应的 Python,由当前路径下的
.python-version
文件决定,可通过pyenv local
命令覆盖该文件的设定通过搜索每一个 parent 路径直到整个文件系统的根路径,找到的第一个
.python-version
文件全局
$(pyenv root)/version
文件,这个文件的内容由命令pyenv global
修改设定。如果不存在,pyenv
就会认定用户想要用的是System Python
关于 系统 Python
,即 PATH
中,Shims
之后能找到的任一 Python。无论是操作系统自带的 Python,还是通过其他软件包如 Homebrew
另外安装的不同版本的 Python,pyenv
对此不做识别区分,谁在 PATH
中排在前面就把谁当 系统 Python
调用。(所以,通过 which python
确认当前使用的版本还是很有必要的,以免误用。)
所有通过 pyenv
安装的 Python 都在 $(pyenv root)/versions
路径下各自对应的路径中。
具体到我本机,pyenv
默认的是安装在 home
的用户路径下,即 ~/.pyenv
(=/home/user_name/.pyenv
),其中就含有上面提到的 version
文件,里面写着 system
,pyenv
对 系统
的理解前面刚已提及(未必真的是操作系统 Python)。除非位于对应虚拟环境的项目路径下,里面会含有 .python-version
文件,注明使用该虚拟环境对应安装的 Python,根据 pyenv
对 Python 版本的选择顺序,会优先被调用。
以上内容啰啰嗦嗦一大堆,其实就是:
如果在虚拟环境对应项目的路径下,如
BeatsTracking
,则默认用它对应的 Python,但是也可以通过pyenv local version_number
临时修改当前想要调用的版本,如此一来,Shell 中输入python
调用的就是local
临时指定的版本。在系统的其他位置,该local
操作也是同理生效。pyenv global
全局默认使用的是系统 Python
,但是也可以通过该命令做不同的设置修改在 Shell 中输入绝对路径调用某一版本 Python,如
~/.pyenv/versions/3.8.7/bin/python
或~/.pyenv/versions/3.8.7/envs/BeatsTracking/bin/python
使用
首先,安装 Python 构建依赖,pyenv
建议的 Ubuntu/Debian/Mint 构建环境:
sudo apt update; sudo apt install build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev curl \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev llvm
#列出所有可供安装的 Python 版本
pyenv install -l
#安装某版本的 Python
pyenv install python-version-number
#查看系统内当前所有的 Python 版本
pyenv versions
#卸载
pyenv uninstall python-version-name
#选定全局性偏向使用的版本
pyenv global python-version-name
#设定局部版本
pyenv local python-version-name
pyenv-virtualenv
pyenv-virtualenv
是 pyenv
的一个插件,用来管理 virtualenv
和 conda
Python 环境。
#以指定的 Python 版本在 $(pyenv root)/versions 路径下新建 name_directory 虚拟环境
pyenv virtualenv python_version_name env_name
#查看已创建的虚拟环境,每个环境会有两个条目,其中一个只是 symlink
pyenv virtualenvs
#删除某个虚拟环境
pyenv uninstall env_name
综上,当为某一个新建的 Python 项目(new_project)创建虚拟环境时,可如下操作:
# 1.安装某一版本的 Python
pyenv install python_version_number
# 2.创建虚拟环境 new_project
pyenv virtualenv python_version_number new_project
# 3.去到新项目所在路径下
cd new_project
# 4.将虚拟环境 Python 设置为该路径(即新项目)默认使用的 Python
# 这个命令会在当前路径下生成一个 .python-version 文件
# 于是这个虚拟环境对应的 Python 二进制文件路径会被放在 $PATH 最前面优先被运行
pyenv local new_project
注:以上命令中,2、4 的 new_project
对应虚拟环境名称,3 中的 new_project
对应同名项目的路径名
Conda
Miniconda 安装与卸载
单独安装与卸载:
# 安装
mkdir -p ~/miniconda3
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh -O ~/miniconda3/miniconda.sh
bash ~/miniconda3/miniconda.sh -b -u -p ~/miniconda3
rm -rf ~/miniconda3/miniconda.sh
# 卸载
rm -rf ~/miniconda3
rm -rf ~/.condarc ~/.conda
使用 pyenv
安装与卸载:
# 默认安装在 ~/.pyenv/versions/ 路径下
pyenv install miniconda3-latest
# 卸载
pyenv uninstall miniconda3-latest
修改 ~/.bashrc 文件,加入 $PATH 环境变量
# 独立安装
~/miniconda3/bin/conda init bash
# 使用pyenv安装
~/.pyenv/versions/miniconda3-latest/bin/conda init bash
更新 conda
conda update conda
创建 conda 虚拟环境同时安装依赖软件
在安装 conda
时同时也安装了一个 Python,这个最外围的 conda 自身所处的环境叫做 base environment
。其中的 Python 也可以理解为 基础(base)Python
,是供 conda 自己依赖使用的,不要动它。前面已讲过,Conda 创建的虚拟环境比较特殊,其中会安装一个独立完整的 Python 专供虚拟环境使用。后续安装依赖时千万小心不要混淆环境错用了 基础 Python
。
# 创建名为 base_py 的虚拟环境同时安装 jupyterlab
conda create -n base_py jupyterlab
# 如果不同时安装 jupyterlab 这些依赖,也可以:
pyenv virtualenv base_py
如上方命令所示,在创建名叫 base_py
的虚拟环境时,同时指定了安装依赖 jupyterlab
,还可以在后面添加更多确定要用的软件,这种同时安装的方式相比逐个安装,能更好地回避依赖冲突问题。
注意:
在 conda 环境下不要使用 pip
安装依赖,万不得已非要用 pip
安装时,那就最后再用,而且先克隆一个相同的虚拟环境再用 pip
安装
激活虚拟环境
参考 pyenv-virtualenv 主页关于 Anaconda 和 Miniconda 部分说明,使用 pyenv
激活。每次手动输入命令过于麻烦,可以在 base_py
路径下执行 pyenv local miniconda3-latest/envs/base_py
生成 .python-version
文件,以后进入该路径会自动激活对应虚拟环境,不需要再做其他操作。(最后面 ## 1221 更新
以及 ## 1222 更新
都与此有关。)
# 激活虚拟环境 base_py
pyenv activate miniconda3-latest/envs/base_py
# 退出虚拟环境状态,回到 base 环境
pyenv deactivate
前面已讲过,激活就会修改 $PATH
环境变量,把这个版本的 Python 二进制文件路径放到最前方。
导出虚拟环境配置文件
# 导出虚拟环境 base_py 的环境配置文件
conda env export -n base_py > environment.yml
这个环境文件(environment.yml
)中记录了 conda base_py
环境中所有已安装的软件及其具体版本,将它放入项目所在仓库,接受 git 版本控制管理。
参考
以下部分纯作记录留存用,无阅读必要。
pyenv
安装的 conda
,还是要归 pyenv
管
1222 更新:通过 按照昨天最后的理解和操作,今天开机发现还是有问题。对 pyenv
和 conda
的理解与使用仍需要校正。前面正文 Conda 使用部分 也已相应修改。因为想要留存记录,不想把 1221 更新
的部分删去,就全都移到了篇尾。
其实很多关键点 pyenv-virtualenv
的官方文档/使用说明从一开始都讲清楚了,但是没有办法,总是后来才缓过神来。
再次梳理一些要点:
pyenv
可以安装各种版本的 Python,其中包括miniconda
这个生态下的pyenv
通过插件pyenv-virtualenv
创建管理 Python 虚拟环境,同上,既包括典型如从virtualenv
顺延下来的依附于某个基础 Python
的虚拟环境,同时也支持conda
类的虚拟环境(这种环境中安装着完整版的 Python)综合以上两条,
pyenv
联合pyenv-virtualenv
就能安装管理系统内各种版本类型的 Python 及其对应虚拟环境pyenv
、conda
、pyenv-virtualenv
都对.bashrc
文件做了修改,于是每次启动命令行/终端的时候,Shell 自动就会对环境变量(如$PATH
)进行配置,完成一些初始化工作(如下图中的pyenv init -
以及pyenv-virtualenv init -
)通过
pyenv
安装的conda
还是受它管理影响,最关键的,激活或关闭某conda
虚拟环境,不再用conda
命令,而是和virtualenv
或venv
类型的虚拟环境相似,都统一用pyenv
命令:pyenv activate env_name pyenv deactivate
我这两天遇到的问题就跟最后一条相关,如果要启用我的 conda
虚拟环境 base_py
,应该输入 pyenv activate miniconda3-latest/envs/base_py
命令。每次这样操作会比较麻烦,所以可以在我的 base_py
文件路径下,通过 pyenv local miniconda3-latest/envs/base_py
命令生成一个 .python-version
文件,如此一来,每当进入该路径后,自动就会激活该虚拟环境,不需要再额外用 conda
或 pyenv
做任何操作。此前,我对此还是有些误解,分析问题产生的原因时存在偏差。
参考:
1221 更新(此部分理解有误,仅作留存,见 1222 更新)
又出了一点问题,从上次搞定之后到昨天都正常,忘记这之间是否有重启过电脑,昨天晚上因为风扇响声太吵而关机,今天开机 conda activate base_py
后运行 Python,pyenv
报错该虚拟环境对应的 Python 未安装......
装是绝对装了,还用呢,肯定也没崩,我猜就是 pyenv
还有 conda
对 $PATH
的管理问题。
下面正文已经详细到啰嗦地交待过,miniconda
我是通过 pyenv
安装的,所以无论是 conda
的基础 base
环境还是它又安装的虚拟环境 base_py
,它们各自对应的 Python 全都归属在 pyenv
的路径下统一管理,即 versions
路径。
一般的,使用某 conda
虚拟环境及其对应 Python,只需要 conda activate env_name
即可,不放心的话就再 conda info -e
确认一下该虚拟环境确实被成功激活了(现在已养成强迫性确认的习惯,生怕用错环境和版本,主要是关系到后续新安装依赖的管理问题)。
因为我同时用 pyenv
,所以此前对本地一个同名 base_py
路径做了 pyenv local miniconda3-latest/envs/base_py
处理,即指定该路径对应使用 base_py
这个虚拟环境对应的 Python,这个操作跟 conda
无关,是 pyenv
的功能,如此一来,这个路径下就会生成一个 .python-version
文件,里面注明当前路径下指定使用的 Python 版本,理论上每次进入到这个路径后,自动就会使用这个版本的 Python。
上面一段删除是说我现在觉得这种操作不好,会影响 conda
的路径管理,例如,在其他路径下 conda activate base_py
会失败报错,而原本虚拟环境的激活跟我处在哪个路径下是没有关系的,我可以在不同的路径下用这同一个环境工作,当然也可以固定在唯一一个路径下使用。
删除上面一段的操作,即不在本机 base_py
路径下生成 pyenv
的 .python-version
文档,也是为了清晰分割 pyenv
和 conda
的功能,即使可以也不混用。不管 pyenv
对于 Python 的版本有何简便管理功能,当前语境下我仅仅用它安装 miniconda
,done。剩下的全都交给 conda
,即安装虚拟环境及对应版本 Python;激活或关闭使用虚拟环境;安装、管理虚拟环境的所有依赖。
再以命令的形式明确一下:
# 安装(卸载直接用 uninstall 替换)
pyenv install miniconda3-latest
# conda 修改 .bashrc
~/.pyenv/versions/miniconda3-latest/bin/conda init bash
# conda 更新自己
conda update conda
# conda 安装新虚拟环境,同时安装项目需要的依赖,同时安相比一个个单独安能更好地回避冲突问题
conda create -n base_py jupyterlab
# 激活某虚拟环境,关闭只需 conda deactivate(不加环境名)
conda activate base_py
# 导出某虚拟环境已安装的所有依赖
conda env export -n base_py > environment.yml
一旦激活某虚拟环境,无论 cd
到哪个路径,按说都应是它。但保险起见,还是 pyenv versions
双重确认一下。
最开始那个问题后来用 pyenv local
再具体指定一下 Python 版本就好了,但是如前面所述,我已删除 .python-version
文件且不打算再让 pyenv
碰虚拟环境。
另外,过程中又看到一篇文章:Relieving your Python packaging pain,作者的观点也算是激进的,就是 pyenv
、conda
这种软件全都不要用,就是尽可能的 Python 纯原生。理解,也有启发,但还是有问题。正如我之前正文中已引用过的,Conda: Myths and Misconceptions 这篇文章已厘清过,conda
的产生是有原因的,就是有纯原生解决不了的问题,这里不再赘述,只是两篇文章贴在一起以备参考。