Domanda

Questo è un follow-up domanda da qui specifica riguardante la sua risposta .


Da un modulo Python che io chiamo un Ciao Mondo eseguibile che stampa semplicemente Hello World al stdout. Sono interessato a reindirizzare l'output a un StringIO pitone e corse in questa risposta che quasi mi porta tutta la strada alla soluzione .

La parte critica di questa risposta è questo segmento di codice:

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

Inoltre vorrei ripristinare lo stdout come era prima il reindirizzamento.

Domande

  1. Che cosa esattamente sta succedendo nella funzione di cui sopra?
    • Qual è dup e dup2 fare?
    • Qual è /dev/null?
    • Qual è la linea 8 facendo? (sys.stdout = os.fdopen(newstdout, 'w'))
  2. Come posso conservare lo stdout in un oggetto StringIO?
  3. Come faccio a ripristinare lo stdout dopo la chiamata al mio Ciao Mondo

Sono abbastanza sicuro che una volta che ho la risposta per la mia domanda 1 che le risposte di domande 2 e 3 sarà facile. Ho deciso di postare loro comunque a forse spingere la risposta alla domanda 1 nella direzione in cui voglio andare.

È stato utile?

Soluzione

ho scritto qui di seguito alcuni commenti aggiuntivi che dovrebbero rendere più chiaro quello che sta succedendo all'interno della funzione redirect_stdout:

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 da notare è che un processo ottiene tre diverse descrittori di file dal sistema operativo quando lanciato:

  • stdin: 0
  • stdout: 1
  • stderr: 2

Come spiegato nei commenti, il codice prende sopra vantaggio del descrittore di file per stdout e le funzioni di descrittore di file di duplicazione per rendere ingannare il codice C ad utilizzare uno stdout diverso pur mantenendo un riferimento al stdout originale nel codice Python per essere in grado di stampare.

Altri suggerimenti

/dev/null è un file speciale dispositivo (tutto in UNIX è un file!) Che inghiotte tutte le cose scritte ad esso come un buco nero. dup duplica un descrittore di file. Se siete abituati a Windows, un descrittore di file in UNIX è un intero speciale che rappresenta un file aperto, è come un handle di file di Windows.

Il programma si apre /dev/null per la scrittura (solo), prendendo una copia del descrittore di file, chiudere il file aperto (perché avere un descrittore di file è sufficiente per UNIX Per scrivere in un file, non è necessario per mantenere la risorse aperte), quindi assegnare il file aperto a sys.stdout.

Ricordate sys è il modulo Python che rappresenta tutti i tipi di risorse specifiche di sistema, come ad esempio il file system. Così, in sys.stdout UNIX rappresenterà /dev/stdout cioè il flusso del sistema STDOUT.

Quindi, in totale, questo codice è ingannare Python a pensare che /dev/null/ è STDOUT così ora ogni volta che il programma scrive STDOUT con, per esempio, la dichiarazione print (funzione nella python3) allora sarà davvero scrivendo a /dev/null e vi non vedere mai il testo risultante sulla tua console.

pagine di manuale per le funzioni di runtime C che stanno alla base di queste funzioni Python.

In sostanza, essi duplicare un descrittore di file, in uno un nuovo descrittore di file (con dup()) oppure in un descrittore di file specificato nella chiamata, con dup2().

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top