subprocess.check_output (), здається, не існує (Python 2.6.5)


79

Я читав документацію Python про модуль підпроцесу (див. Тут ), і там йдеться про subprocess.check_output()команду, яка, здається, саме те, що мені потрібно.

Однак, коли я намагаюся використовувати його, я отримую повідомлення про те, що воно не існує, а коли я dir(subprocess)його запускаю, його немає в списку.

У мене запущений Python 2.6.5, і код, який я використовував, наведений нижче:

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

Хтось уявляє, чому це відбувається?

Відповіді:


123

Це було введено в 2.7 Див. Документи .

Використовуйте підпроцес .

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

14
на відміну від check_output, це не підвищується, CalledProcessErrorколи процес повертає ненульовий код повернення.
Шрідхар Ратнакумар

1
@SridharRatnakumar: звичайно, тому що між ними є велика різниця, а саме: блокування та неблокування. Вони призначені для різних випадків використання!
lpapp

Я штовхнув його в lambdaтак: check_output = lambda args: Popen(args, stdout = PIPE).communicate()[0]. Просто тому, що я працюю в інтерактивному інтерпретаторі, і це свого роду PITA - виписувати багаторядкові функції defs в них. Я використовував from subprocess import Popen, PIPEраніше на сесії.
ArtOfWarfare

як зробити пінг тоді ?? чи можу я все-таки використовувати Popen або?
TheCrazyProfessor

56

ЯКЩО він інтенсивно використовується в коді, який ви хочете запустити, але цей код не повинен підтримуватися довгостроково (або вам потрібне швидке виправлення, незалежно від потенційних головних болів у технічному обслуговуванні в майбутньому), тоді ви можете схилити удар (він же патч мавпи) це там, де імпортується підпроцес ...

Просто підніміть код з 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, ви а) повинні це помітити та б) оновити свою версію, якщо хочете бути захищеними. Крім того, перевизначення та визначення внутрішніх функцій - це найгірший кошмар наступного хлопця, особливо коли наступний хлопець - ВАС кілька років тому, і ви забули все про грубі хаки, які ви робили минулого разу! Підсумовуючи: дуже рідко це хороша ідея.


2
Я погоджуюся з цим методом. Можливо, я б включив місце розташування джерела. Ви можете знайти його за адресою hg.python.org/cpython/file/d37f963394aa/Lib/subprocess.py#l544
Ехтеш Чоудхурі

1
Примітка: CalledProcessError не приймає вихід у python 2.6. (Мене одразу покусали після використання цього хака! :()
Енді Хейден,

cpython тепер на GitHub - check_outputдля Python 2.7 зараз тут: github.com/python/cpython/blob/2.7/Lib/subprocess.py#L194
jamesc

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.