2011-03-04 21 views
12

El módulo subproceso tiene la función de conveniencia call, que se implementa como éste, tanto en 2.6 y 3.1:¿Por qué el subprocess.call de python se implementa así?

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

La documentación para esta función lleva una advertencia de color rojo, la lectura:

Advertencia : Al igual que Popen.wait(), se bloqueará cuando se usen stdout=PIPE y/o stderr=PIPE y el proceso secundario genera suficiente salida a una tubería de manera que bloquea la espera de que el búfer de la tubería del SO acepte más datos.

La documentación Popen.wait() dice que use Popen.communicate() lugar en tales circunstancias. Bueno, entonces ¿por qué no se implementa call como se muestra abajo, por lo que se puede eliminar la estúpida advertencia y se pueden eliminar limitaciones estúpidas 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?

Respuesta

8

pasé algún tiempo mirando a través PEP-324, que introdujo el módulo de subproceso, tratando de averiguar las decisiones de diseño involucrados, pero creo que la respuesta es muy simple:

Hay ninguna razón pasar stdout=PIPE o stderr=PIPE a subprocess.call, por lo que el hecho de que pueda llegar a un punto muerto es irrelevante.

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

Existe una sobrecarga potencial de Popen.communicate (crear hilos adicionales para evitar interbloqueo mediante el control de las tuberías), y no hay ningún beneficio en este caso, por lo que no hay ninguna razón para usarlo.

Editar: Si desea descartar su salida, supongo que es mejor hacerlo de forma explícita:

# 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 instruir subproceso para capturar toda la salida a archivos tubería que nunca tuvo la intención de utilizar.

+0

El control de la salida del programa es un reson para usar stdout = PIPE y stderr = PIPE. Es decir, el equivalente de python de 'comando>/dev/null 2> & 1' y luego verificando '$?' En bash. –

+0

¿No sería mejor hacerlo con 'stdout = open ('/ dev/null', 'w'), stderr = STDOUT'? –

+0

@Baffe, supongo, pero el punto es que existe una razón para utilizar los argumentos stdout = y stderr = keyword de 'call'. –

2

Si todo lo que quiere hacer es ejecutar un comando y obtener el estado de salida para determinar si tuvo éxito o falló, entonces no necesita comunicarse con él a través de las tuberías. 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 utilice call(), use un objeto Popen y comuniquese con él() como el estado de los documentos.

Cuestiones relacionadas