2011-03-04 63 views
12

子流程模块具有便利功能call,这是在两个2.6和3.1实现这样的:为什么python的subprocess.call像这样实现?

def call(*popenargs, **kwargs): 
    return Popen(*popenargs, **kwargs).wait() 

此函数的文档携带红色警告,内容如下:

警告 :与Popen.wait()类似,当使用stdout=PIPE和/或stderr=PIPE时,此过程会发生死锁,并且子进程会向管道生成足够的输出,从而阻止等待OS管道缓冲区接受更多数据。

Popen.wait()文档说在这种情况下使用Popen.communicate()。那么,为什么不是call只是像下面的实现,所以愚蠢的警告可以被删除,像这样的愚蠢限制从标准库中删除?

def call(*args, **kwargs): 
    input = kwargs.pop("input", None) 
    p = Popen(*args, **kwargs) 
    p.communicate(input) 
    return p.returncode 

我确定有一个原因。我错过了什么?

回答

8

我花了一些时间翻翻PEP-324,其推出的子模块,试图找出设计决策参与,但我想答案其实很简单:

没有理由通过stdout=PIPEstderr=PIPEsubprocess.call,所以它可以死锁的事实是无关紧要的。

的唯一原因传递stdout=PIPEstderr=PIPEsubprocess.Popen是让你可以使用POPEN实例的stdoutstderr文件对象属性的。由于subprocess.call永远不会让您看到Popen实例,因此PIPE选项变得无关紧要。

有潜在的开销Popen.communicate(通过监视管道创建其他线程以避免死锁),在这种情况下没有任何好处,所以没有理由使用它。

编辑:如果你要放弃你的输出,我想这是最好明确地这样做:

# option 1 
with open(os.devnull, 'w') as dev_null: 
    subprocess.call(['command'], stdout=dev_null, stderr=dev_null) 

# option 2 
subprocess.call(['command >& /dev/null'], shell=True) 

,而不是指示子到所有的输出捕捉到PIPE文件,你从来没有打算使用。

+0

控制程序的输出是使用stdout = PIPE和stderr = PIPE的共同点。也就是,相当于'command>/dev/null 2>&1'的python,然后在bash中检查'$?'。 – 2011-03-04 15:33:37

+0

'stdout = open('/ dev/null','w'),stderr = STDOUT'会更好吗? – 2011-03-04 15:48:23

+0

@Baffe我想,但重点是,有一个理由使用'call'的stdout =和stderr =关键字参数。 – 2011-03-04 15:53:08

2

如果您只想运行命令并获取退出状态以确定它是成功还是失败,那么您不需要通过管道与它进行通信。这是subprocess.call()方法的便利。在子过程模块中还有其他便利功能,它们封装了以高效方式使用Popen对象的许多常见用途。

如果您需要将子进程的标准输出或标准错误输出到不使用call()的地方,请使用Popen对象并与其通信(),就像文档状态一样。

相关问题