Подтвердить что ты не робот

Почему python subprocess.call реализован так?

Модуль подпроцесса имеет удобную функцию call, которая реализована как в 2.6, так и 3.1:

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

Я уверен, что есть причина. Что мне не хватает?

4b9b3361

Ответ 1

Я потратил некоторое время на поиск PEP-324, в котором был представлен модуль подпроцесса, пытаясь выяснить, какие проектные решения задействованы, но я думаю ответ на самом деле очень прост:

Там нет причины передать stdout=PIPE или stderr=PIPE в subprocess.call, поэтому тот факт, что он может быть заблокирован, не имеет значения.

Единственная причина перехода stdout=PIPE или stderr=PIPE в subprocess.Popen заключается в том, что вы можете использовать атрибуты экземпляра Popen stdout и stderr как объекты файлов. Поскольку 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, которые вы никогда не собираетесь использовать.

Ответ 2

Если все, что вы хотите сделать, это запустить команду и получить статус выхода, чтобы определить, удалось ли это или не удалось, вам не нужно связываться с ней через каналы. Это удобство метода subprocess.call(). Существуют и другие функции удобства в модуле подпроцесса, которые инкапсулируют многие из общих применений эффективного использования объектов Popen.

Если вам нужно связать дочерние процессы stdout или stderr где-нибудь, а не использовать call(), используйте объект Popen и обменивайтесь() с ним точно так же, как состояние документов.