Pregunta

Esta es una pregunta de seguimiento de aquí específicamente sobre su responder.


De un módulo de pitón llamo a un Hola Mundo ejecutable que simplemente imprime Hello World al stdout. Estoy interesado en redirigir esa salida a una pitón StringIO y se topó con este Responda que casi me lleva hasta la solución.

La parte crítica de esta respuesta es este segmento de código:

1. def redirect_stdout():
2.     print "Redirecting stdout"
3.     sys.stdout.flush() # <--- important when redirecting to files
4.     newstdout = os.dup(1)
5.     devnull = os.open('/dev/null', os.O_WRONLY)
6.     os.dup2(devnull, 1)
7.     os.close(devnull)
8.     sys.stdout = os.fdopen(newstdout, 'w')

También me gustaría restaurar el stdout como era antes de la redirección.

Preguntas

  1. ¿Qué está pasando exactamente en la función anterior?
    • Que es dup y dup2 ¿haciendo?
    • Que es /dev/null?
    • ¿Qué está haciendo la línea 8? (sys.stdout = os.fdopen(newstdout, 'w'))
  2. ¿Cómo puedo almacenar el stdout en un StringIO ¿objeto?
  3. ¿Cómo puedo restaurar el stdout después de la llamada a mi Hola Mundo ¿programa?

Estoy bastante seguro de que una vez que tenga la respuesta para mi pregunta 1, las respuestas de las preguntas 2 y 3 serán fáciles. Decidí publicarlos de todos modos para empujar la respuesta de la pregunta 1 en la dirección a la que quiero ir.

¿Fue útil?

Solución

He escrito a continuación algunos comentarios adicionales que deberían aclarar lo que está pasando dentro del redirect_stdout función:

def redirect_stdout():
    print "Redirecting stdout"
    sys.stdout.flush() # <--- important when redirecting to files

    # Duplicate stdout (file descriptor 1)
    # to a different file descriptor number
    newstdout = os.dup(1)

    # /dev/null is used just to discard what is being printed
    devnull = os.open('/dev/null', os.O_WRONLY)

    # Duplicate the file descriptor for /dev/null
    # and overwrite the value for stdout (file descriptor 1)
    os.dup2(devnull, 1)

    # Close devnull after duplication (no longer needed)
    os.close(devnull)

    # Use the original stdout to still be able
    # to print to stdout within python
    sys.stdout = os.fdopen(newstdout, 'w')

Una cosa importante a tener en cuenta es que un proceso tiene tres diferentes descriptores de archivo Desde el sistema operativo cuando se lanza:

  • Stdin: 0
  • stdout: 1
  • Stderr: 2

Como se explicó en los comentarios, el código anterior aprovecha el descriptor del archivo para stdout y el descriptor de archivo de la duplicación de la duplicación para hacer truco el código C en el uso de un stdout diferente mientras mantiene una referencia al stdout original en el código de python para poder poder poder poder imprimir.

Otros consejos

/dev/null es un archivo de dispositivo especial (¡todo en UNIX es un archivo!) Que se lo traga todo escrito como un agujero negro. dup Duplica un descriptor de archivo. Si está acostumbrado a Windows, un descriptor de archivo en UNIX es un entero especial que representa un archivo abierto, es como un identificador de archivo de Windows.

El programa se está abriendo /dev/null Para escribir (solo), tomar una copia de su descriptor de archivo, cerrar el archivo abierto (porque tener un descriptor de archivo es suficiente para que Unix escriba en un archivo, no necesita mantener los recursos abiertos) y luego asignar el Abierto presentar a sys.stdout.

Recuerda sys es el módulo Python que representa todo tipo de recursos específicos del sistema, como el sistema de archivos. Entonces, en Unix sys.stdout representará /dev/stdout es decir, el sistema STDOUT corriente.

Entonces, en total, este código está engañando a Python para que piense que /dev/null/ es STDOUT Así que ahora cada vez que su programa escribe para STDOUT con, digamos, el print Declaración (función en python3) entonces realmente se escribirá para /dev/null Y nunca verá el texto resultante en su consola.

Ver páginas manuales para las funciones de tiempo de ejecución C que subyacen a estas funciones de Python.

Básicamente, duplican un descriptor de archivo, en un nuevo descriptor de archivo (con dup()) o en un descriptor de archivo especificado en la llamada, con dup2().

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top