在不同虚拟环境中运行子进程与Python
假设我在两个不同的虚拟环境中安装了我的应用程序,分别是 myapp v1.0 和 myapp v2.0。
现在我想比较这两个版本。这个比较是用 Python 编写的。我该怎么做比较比较好呢?假设我可以分别运行它们,并且它们都能写出一个输出文件,方便我之后进行比较。
一种方法是写一个 bash 脚本(我现在就是这么做的)。我先激活一个虚拟环境,运行 myapp v1.0,然后激活另一个虚拟环境,运行 myapp v2.0。之后再对这些文件运行一个比较模块。但我想让这个过程更灵活一些(比如添加一些可选参数等),用 Python 来做会更简单。
目前我有这样的一个 bash 脚本:
source virtualenv1/bin/activate
python my_script.py
deactivate
source virtualenv2/bin/activate
python my_other_script.py
deactivate
python my_comparison_script.py
而我想要的只是:
python my_comparison_script.py
这样我的脚本就可以在这个环境中运行。
3 个回答
一个简单的方法是使用subprocess来运行一系列命令,具体做法如下(注意,shell=True
是有风险的,只有在你能控制输入的情况下才应该使用)。
import subprocess
cmd = 'source activate my_virtualenv; python my_script.py'
subprocess.call(cmd, shell=True, executable='/bin/bash')
根据需要重复这个过程。
我觉得virtualenv的文档解释得很好。
简而言之
直接运行python的venv二进制文件并不等同于激活venv。你还需要相应地更改PATH和VIRTUAL_ENV这两个变量(可以查看os.environ)。
$ source /path/to/ENV/bin/activate
这条命令会改变你的$PATH,让它的第一个条目指向虚拟环境的bin/目录。(你必须使用source,因为它会直接在你的命令行环境中进行更改。)这就是它的全部功能;纯粹是为了方便。
如果你直接从虚拟环境的bin/目录运行一个脚本或python解释器(比如/path/to/ENV/bin/pip或/path/to/ENV/bin/python-script.py),那么sys.path会自动设置为使用与虚拟环境相关的Python库。但是,与激活脚本不同,环境变量PATH和VIRTUAL_ENV不会被修改。这意味着,如果你的Python脚本使用例如subprocess来运行另一个Python脚本(比如通过!/usr/bin/env python这行代码),那么第二个脚本可能不会使用与第一个脚本相同的Python二进制文件,也可能没有相同的库可用。为了避免这种情况,你的第一个脚本需要在执行第二个脚本之前,像激活脚本那样修改环境变量。
如果你是通过调用python可执行文件来启动你的应用程序,就像你示例中的那样,其实这非常简单:你只需要明确指向虚拟环境中的可执行文件。
import subprocess
subprocess.Popen(["virtualenv1/bin/python", "my_script.py"])
subprocess.Popen(["virtualenv2/bin/python", "my_other_script.py"])
这样就会在各自的虚拟环境中启动进程。
重要提示
针对评论中提到的担忧:
如果你想要运行一个子进程,并且确保使用的是当前进程正在运行的相同解释器,你需要使用sys.executable。另外,还有sys.exec_prefix可以用来访问特定于站点的目录前缀,那里安装了与平台相关的Python文件。
如果你想更深入地讨论这个话题,可以看看这个拉取请求。