虚拟环境的好处都有啥,谁说对了就给它~

在学校里已经在许多场合反复给不少人科普过虚拟环境的面向需求、优势和必要性,在这么发达的互联网上就不再赘述了。

不过呢,有些时候脑梗忘记激活到对应的虚拟环境就运行脚本,还是有点令人哑火的。

我使用的方案是 pythonvenv 模块,虚拟环境放置在对应项目根目录下的 .venv 内。环境是跟项目的,所以还是很好找到 python 文件对应需要启动的项目。因此就写了一个自动化脚本,来实现在绝大部分通用场景下,对这一布局的虚拟环境自动激活的需求。

在下文,我们称这个 虚拟环境自动激活脚本vpy

脚本分析

首先啊首先,我们需要明确一下需求,我希望对 vpy 的调用方式,如果在正常地使用 python 去执行 python文件 一般,这样才能够方便迁移和使用。

也就是提供以下对应调用语法:

1
2
3
python script.py arg1 arg2 arg3 ...
---
vpy script.py arg1 arg2 arg3 ...

因此我们需要先将输入 vpy 的输入参数分为两部分,其中第一个参数为 待执行目标,后续参数为 目标输入参数

注意 待执行目标 通常为一个 python文件 相对路径,由于我们后续还要处理路径关系,找到其所在目录,来进一步找到虚拟环境。为了规避相对路径的父子目录切换可能存在的问题,在这里我们还需要通过 realpath 先将python文件 相对路径转为绝对路径。

也就是如下代码:

1
2
3
script_path=$(realpath $1)
shift
args=$@

接着我们期望获取到 python文件 的所在目录,并通过判断该目录下是否存在 .venv 目录以及是否存在虚拟环境激活脚本来判断该项目是否使用了虚拟环境。

也就是如下代码:

1
2
3
4
5
6
7
8
9
venv_dir="${script_dir}/.venv"
bin_dir="${venv_dir}/bin/activate"
if [ -d "${venv_dir}" ] && [ -f "${bin_dir}" ]; then
    # ...
    # 使用虚拟环境
else
    # ...
    # 未使用虚拟环境
fi

当使用了虚拟环境时,则激活它,否则将不进行任何操作。

也就是如下代码:

1
source "${bin_dir}"

至此,vpy 上下文中所使用的 python 已经根据项目是否使用虚拟环境,而保持在全局解释器/切换为虚拟环境解释器。

那么剩下的最后工作,就是把开头提取出来的 待执行目标目标输入参数 传递给 python 来实际解释运行即可。

也就是如下代码:

1
python ${script_path} ${args}

可以通过以下代码来输出当前上下文环境信息,来校验 vpy 执行情况:

1
2
3
4
5
6
echo "[vpy]工作目录:$(pwd)
[vpy]解释器:$(which python)
[vpy]执行目标:${script_path}
[vpy]输入参数:${args}
[vpy]执行脚本...
"

可以整体还是非常简单的,都是基本语法和设施。

效果演示

python文件 内容:

1
2
3
4
5
import os
import sys

if __name__ == "__main__" :    
    print(f"[main.py]使用解释器{sys.executable}, 工作目录{os.getcwd()}, 输入参数{sys.argv[1:]}")

后话

最后只要通过 alias 将脚本别名为 vpy,即可抛弃显式通过路径调用脚本,最终达到开头实现的效果了。

其他虚拟环境或操作系统按照类似思路即可实现效果。

不得不说,主力系统用了 Linux 之后,面对这种公式化的需求,越来越习惯于自己写一个脚本来简化流程步骤,提高生产力了(大概)~