¿Por qué se implementa subprocess.call de python de esta manera?

El módulo de subproceso tiene la función de call conveniencia, que se implementa de esta manera en 2.6 y 3.1:

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

La documentación para esta función lleva una advertencia roja, leyendo:

Advertencia : al igual que Popen.wait() , esto se interrumpirá al usar stdout=PIPE y / o stderr=PIPE y el proceso hijo genera suficiente salida a una tubería de tal manera que bloquea la espera de que el búfer de tubería del sistema operativo acepte más datos.

La documentación de Popen.wait() dice que se debe usar Popen.communicate() en tales circunstancias. Bueno, entonces, ¿por qué no se implementa la call simplemente como se muestra a continuación, para que se pueda eliminar la estúpida advertencia y se eliminen tonterías limitaciones como esta de la biblioteca estándar?

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

Estoy seguro de que hay una razón. ¿Qué me estoy perdiendo?

Pasé un tiempo mirando a través de PEP-324 , que introdujo el módulo de subproceso, tratando de averiguar las decisiones de diseño involucradas, pero creo que la respuesta es en realidad muy simple:

No hay razón para pasar stdout=PIPE o stderr=PIPE a subprocess.call , por lo que el hecho de que pueda interrumpirse es irrelevante.

La única razón para pasar stdout=PIPE o stderr=PIPE a subprocess.Popen es para que pueda usar los atributos stdout y stderr la instancia de Popen como objetos de archivo. Como subprocess.call nunca te permite ver la instancia de Popen, las opciones de PIPE se vuelven irrelevantes.

Popen.communicate tiene una sobrecarga potencial (creando subprocesos adicionales para evitar el interlocking al monitorear las tuberías), y no hay beneficios en este caso, por lo que no hay razón para usarlo.

Edición : si desea descartar su salida, creo que es mejor hacerlo explícitamente:

 # 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) 

en lugar de dar instrucciones al subproceso para capturar toda la salida a archivos PIPE que nunca pretende usar.

Si todo lo que desea hacer es ejecutar un comando y obtener el estado de salida para determinar si tuvo éxito o no, entonces no necesita comunicarse con él a través de canalizaciones. Esa es la conveniencia del método subprocess.call (). También hay otras funciones de conveniencia en el módulo de subproceso que encapsulan muchos de los usos comunes del uso de los objetos Popen de una manera eficiente.

Si necesita canalizar los procesos secundarios stdout o stderr en algún lugar que no use call (), use un objeto Popen y comuníquese () con él como indica el estado.