我已经尝试了解
subprocess.call
和subprocess.run
之间的区别有一段时间了。我知道最后一个是 Python 3.5 的新功能,并且两者都基于 subprocess.Popen
,但我还无法理解其中的区别。
subprocess.call()
的定义明确提到:
相当于:
(除了不支持 input 和 check 参数)run(...).returncode
正如Python 3.5的子流程文档所说:
在 Python 3.5 之前,这三个函数(即
、.call()
、.check_call()
)构成了子进程的高级 API。您现在可以在许多情况下使用.check_output()
,但许多现有代码都会调用这些函数。run()
常见的做法是,当某些功能被替换时,它们不会立即弃用,但某些版本有一个支持窗口。这有助于防止语言版本升级时旧代码的损坏。不知道以后
.call()
会不会被取代。但根据文档,我知道它们几乎相同。
为了让任何想知道使用哪个的人都清楚:
subprocess.run() 是它可以处理的所有用例的推荐方法。 suprocess 文档 指出:
调用子流程的推荐方法是对它可以处理的所有用例使用 run() 函数。对于更高级的用例,可以直接使用底层的Popen接口。
subprocess.call() 是较旧的高级 API(Python 3.5 之前)的一部分。
我不确定我是否同意其他答案。
我刚刚使用启动守护进程(Elasticsearch)的 bash 脚本度过了一段非常令人沮丧的时光。该命令仅提供可执行 Bash 脚本的路径。
但是
subprocess.run(...)
不会从此返回,而 subprocess.call(...)
会返回。
根据我的经验,如果您随后使用
subprocess.run(...)
停止该进程(例如,如果从终端运行,则为终端),这将杀死其中启动的守护进程。但 subprocess.call(...)
的情况并非如此:守护进程愉快地继续运行。
在这两种情况下我都设置了 kwarg
shell=True
。
我也尝试过
subprocess.run
ẁithshell=False
(即如果省略shell
则默认):没有变化。
我在
subprocess.run
中看不到任何其他可能的选项可以克服这个问题,所以据我所知,subprocess.call
是根本不同的,尽管文档似乎这么说。在撰写本文时,文档说“您现在可以在许多情况下使用 run(),但许多现有代码都会调用这些函数。” (即旧功能,包括 call
)。
特别奇怪且令人沮丧的是(显然)当您运行启动守护程序的脚本时,例如:
./bin/elasticsearch -d -p pid
...它刚刚返回,您可以非常愉快地关闭终端。所以
subprocess.run
看起来有些奇怪,一些超级专家可能愿意解释一下。
subprocess.call() 用于当您需要执行命令并让它等待命令完全完成时。当需要更多控制时,应使用 subprocess.run(),例如处理命令 stderr 和 stdout、捕获输出并能够定义命令执行超时。
如果我们不关心命令的输出,那么这样的例子是:
subprocess.call([r'C:\Program Files\Mozilla Firefox\Firefox.exe', '-new-tab', 'http://www.google.com/'])
subprocess.call 只捕获您调用的子进程的返回代码
subprocess.run 除了返回代码之外,还允许您使用管道捕获 stdout 和 stdrr 输出
subprocess.run(
[
os.path.normpath(
os.path.join(os.path.dirname(os.environ.get("comspec")), "wbem", "wmic.exe")
),
"csproduct",
"get",
"UUID",
],
stdout=subprocess.PIPE,
shell=True,
).stdout.splitlines(),
需要强调的是,Run 和 Call 都是阻塞的,如果您需要保持它们并行执行或需要更高级的功能,您应该使用 subprocess.Popen,它并行运行并具有更高级的功能
我也不太清楚其中的差异。
我可以说,当您希望程序等待该进程完成然后再进入下一个进程时,您可以使用
subprocess.call()
。在subprocess.run()
的情况下,程序将尝试一次运行所有进程,不可避免地导致程序崩溃。