似乎都执行一个子进程并创建一个进/出的管道,只是它subprocess
更新.
我的问题是,有什么功能subprocess.Popen
可以做而os.popen
不能,所以我们需要新的模块subprocess
?
为什么Python语言没有选择增强os.popen
但是创建了一个新模块?
简答:永远不要使用os.popen
,永远使用subprocess
!
正如您在Python 2.7 os.popen
文档中看到的那样:
从版本2.6开始不推荐使用:此功能已过时.使用该
subprocess
模块.请特别检查" 使用子过程模块替换旧函数"部分.
旧os.popen
功能系列存在各种限制和问题.正如文档所提到的,2.6之前的版本在Windows上甚至都不可靠.
PEP 324中subprocess
解释了背后的动机- 子流程 - 新流程模块:
动机
启动新进程是任何编程语言中的常见任务,并且在Python等高级语言中非常常见.需要对此任务提供良好支持,因为:
用于启动进程的不适当函数可能意味着存在安全风险:如果程序是通过shell启动的,并且参数包含shell元字符,则结果可能是灾难性的.[1]
它使Python成为过于复杂的shell脚本的更好的替代语言.
目前,Python具有大量用于创建流程的不同功能.这使开发人员难以选择.
子进程模块提供了以前功能的以下增强功能:
一个"统一"模块提供以前功能的所有功能.
跨进程异常:在新进程开始执行之前在子进程中发生的异常在父进程中重新引发.这意味着,例如,处理exec()失败很容易.例如,使用popen2,无法检测执行是否失败.
用于在fork和exec之间执行自定义代码的钩子.这可以用于,例如,改变uid.
没有隐式调用/ bin/sh.这意味着不需要转义危险的shell元字符.
文件描述符重定向的所有组合都是可能的.例如,"python-dialog"[2]需要生成一个进程并重定向stderr,但不是stdout.如果不使用临时文件,这对于当前功能是不可能的.
使用子进程模块,可以控制是否应在执行新程序之前关闭所有打开的文件描述符.
支持连接多个子进程(shell"管道").
通用换行支持.
一个communic()方法,它可以轻松发送stdin数据并读取stdout和stderr数据,而不会有死锁的风险.大多数人都知道与子进程通信有关的流控制问题,但并非所有人都有耐心或技巧来编写完全正确且无死锁的选择循环.这意味着许多Python应用程序包含竞争条件.标准库中的communic()方法解决了这个问题.
请参阅PEP链接了解基本原理,以及更多详细信息.
除了安全性和可靠性问题,恕我直言,这个老os.popen
家庭既麻烦又令人困惑.如果没有在编码时仔细引用文档,几乎不可能正确使用.相比之下,这subprocess
是天赐之物,尽管在使用文档时引用文档仍然是明智之举.;)
偶尔会看到人们推荐使用os.popen
而不是subprocess.Popen
Python 2.7,例如Python子进程与os.popen开销,因为它更快.当然,它更快,但这是因为它没有做各种事情,这些事情对于保证它安全运行至关重要!
FWIW os.popen
本身仍然存在于Python 3中,但它通过安全实现subprocess.Popen
,因此您可以subprocess.Popen
直接自己使用.os.popen
Python 3中不再存在该系列的其他成员.os.spawn
函数系列仍然存在于Python 3中,但是文档建议subprocess
使用模块提供的功能更强大的设施.