subprocess.check_output()似乎不存在(Python 2.6.5)

79 投票
3 回答
58771 浏览
提问于 2025-04-16 10:42

我在看Python的文档,特别是关于subprocess模块的部分(可以在这里找到)。文档里提到有个subprocess.check_output()命令,听起来正是我需要的。

可是,当我尝试使用这个命令时,出现了一个错误,提示这个命令不存在。而且当我运行dir(subprocess)时,它也没有在列表中。

我现在使用的是Python 2.6.5,下面是我用的代码:

import subprocess
subprocess.check_output(["ls", "-l", "/dev/null"])

有没有人知道为什么会这样呢?

3 个回答

6

感谢猴子补丁的建议(虽然我尝试了几次都失败了 - 但我们需要处理CalledProcessError的输出,所以需要用猴子补丁来解决这个问题)

我在这里找到了一个可以用的2.6版本的补丁:http://pydoc.net/Python/pep8radius/0.9.0/pep8radius.shell/

"""Note: We also monkey-patch subprocess for python 2.6 to
give feature parity with later versions.
"""
try:
    from subprocess import STDOUT, check_output, CalledProcessError
except ImportError:  # pragma: no cover
    # python 2.6 doesn't include check_output
    # monkey patch it in!
    import subprocess
    STDOUT = subprocess.STDOUT

    def check_output(*popenargs, **kwargs):
        if 'stdout' in kwargs:  # pragma: no cover
            raise ValueError('stdout argument not allowed, '
                             'it will be overridden.')
        process = subprocess.Popen(stdout=subprocess.PIPE,
                                   *popenargs, **kwargs)
        output, _ = process.communicate()
        retcode = process.poll()
        if retcode:
            cmd = kwargs.get("args")
            if cmd is None:
                cmd = popenargs[0]
            raise subprocess.CalledProcessError(retcode, cmd,
                                                output=output)
        return output
    subprocess.check_output = check_output

    # overwrite CalledProcessError due to `output`
    # keyword not being available (in 2.6)
    class CalledProcessError(Exception):

        def __init__(self, returncode, cmd, output=None):
            self.returncode = returncode
            self.cmd = cmd
            self.output = output

        def __str__(self):
            return "Command '%s' returned non-zero exit status %d" % (
                self.cmd, self.returncode)
    subprocess.CalledProcessError = CalledProcessError
58

如果你要运行的代码中大量使用了某个功能,但这些代码不需要长期维护(或者你需要一个快速解决方案,不管将来可能带来的维护麻烦),那么你可以在导入subprocess的地方进行“鸭子打补丁”(也叫“猴子补丁”)...

只需从2.7版本中提取相关代码,然后这样插入...

import subprocess

if "check_output" not in dir( subprocess ): # duck punch it in!
    def f(*popenargs, **kwargs):
        if 'stdout' in kwargs:
            raise ValueError('stdout argument not allowed, it will be overridden.')
        process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)
        output, unused_err = process.communicate()
        retcode = process.poll()
        if retcode:
            cmd = kwargs.get("args")
            if cmd is None:
                cmd = popenargs[0]
            raise subprocess.CalledProcessError(retcode, cmd)
        return output
    subprocess.check_output = f

可能需要进行一些小调整。

不过要记住,维护这些“脏补丁”的责任在你。如果在最新的Python版本中发现并修复了错误,你就得 a) 注意到这一点,b) 如果想保持安全,就得更新你的版本。此外,自己重写和定义内部函数会让后续的开发者非常头疼,尤其是当几年后你自己再来维护时,你可能会忘记之前做的那些“黑科技”了!总的来说:这通常不是个好主意。

123

这个功能是在2.7版本中引入的,详细信息可以查看文档

如果你想获取输出,可以使用subprocess.Popen

>>> import subprocess
>>> output = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE).communicate()[0]

撰写回答