stdout Redirect in pitone per le chiamate C
-
26-10-2019 - |
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
- Che cosa esattamente sta succedendo nella funzione di cui sopra?
- Qual è
dup
edup2
fare? - Qual è
/dev/null
? - Qual è la linea 8 facendo? (
sys.stdout = os.fdopen(newstdout, 'w')
)
- Qual è
- Come posso conservare lo stdout in un oggetto
StringIO
? - 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.
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()
.