我什么时候应该使用 subprocess.Popen 而不是 os.popen?

When should I use subprocess.Popen instead of os.popen?

似乎既执行了一个子进程又创建了一个管道来做 in/out,只是 subprocess 更新了。

我的问题是,有没有什么功能是subprocess.Popen可以做而os.popen不能做的,所以我们需要新模块subprocess

为什么Python语言没有选择增强os.popen而是创建了一个新模块?

简短回答:从不使用 os.popen,始终使用 subprocess

从Python 2.7可以看出 os.popen docs:

Deprecated since version 2.6: This function is obsolete. Use the subprocess module. Check especially the Replacing Older Functions with the subprocess Module section.

旧的 os.popen 系列函数存在各种限制和问题。正如文档所提到的,2.6 之前的版本在 Windows.

上什至不可靠

subprocess 背后的动机在 PEP 324 -- subprocess - New process module 中有解释:

Motivation

Starting new processes is a common task in any programming language, and very common in a high-level language like Python. Good support for this task is needed, because:

  • Inappropriate functions for starting processes could mean a security risk: If the program is started through the shell, and the arguments contain shell meta characters, the result can be disastrous. [1]

  • It makes Python an even better replacement language for over-complicated shell scripts.

Currently, Python has a large number of different functions for process creation. This makes it hard for developers to choose.

The subprocess module provides the following enhancements over previous functions:

  • One "unified" module provides all functionality from previous functions.

  • Cross-process exceptions: Exceptions happening in the child before the new process has started to execute are re-raised in the parent. This means that it's easy to handle exec() failures, for example. With popen2, for example, it's impossible to detect if the execution failed.

  • A hook for executing custom code between fork and exec. This can be used for, for example, changing uid.

  • No implicit call of /bin/sh. This means that there is no need for escaping dangerous shell meta characters.

  • All combinations of file descriptor redirection is possible. For example, the "python-dialog" [2] needs to spawn a process and redirect stderr, but not stdout. This is not possible with current functions, without using temporary files.

  • With the subprocess module, it's possible to control if all open file descriptors should be closed before the new program is executed.

  • Support for connecting several subprocesses (shell "pipe").

  • Universal newline support.

  • A communicate() method, which makes it easy to send stdin data and read stdout and stderr data, without risking deadlocks. Most people are aware of the flow control issues involved with child process communication, but not all have the patience or skills to write a fully correct and deadlock-free select loop. This means that many Python applications contain race conditions. A communicate() method in the standard library solves this problem.

请参阅 PEP link 了解基本原理和更多详细信息。

除了安全性和可靠性问题,恕我直言,旧的 os.popen 系列既麻烦又令人困惑。在编写代码时,如果不仔细参考文档,几乎不可能正确使用。相比之下,subprocess 是天赐之物,尽管在使用它时参考文档仍然是明智的。 ;)

偶尔,有人会建议在 Python 2.7 中使用 os.popen 而不是 subprocess.Popen,例如 Python subprocess vs os.popen overhead,因为它更快。当然,它更快,但那是因为它没有做各种对保证其安全工作至关重要的事情!


FWIW,os.popen itself still exists in Python 3,但是它是通过 subprocess.Popen 安全实现的,所以您最好自己直接使用 subprocess.Popenos.popen家族的其他成员不再存在于Python3中。os.spawn家族的功能仍然存在于Python3中,但文档推荐更强大的设施由 subprocess 模块提供,改为使用。