Sto lavorando in Python 3.4, e ho un comportamento che non capisco: se reindirizzamento allo stdout su un file, sono in grado di catturare il testo da processi figlio . Tuttavia, quando reindirizzo a un oggetto file Python, interrompo l'acquisizione di quell'output. Mi piacerebbe una spiegazione del comportamento (seguente).Reindirizzare `sys.stdout` in un file o un buffer
ho:
from multiprocessing import Process
def worker():
print('forked output')
def output():
print('redirected')
p = Process(target=worker)
p.daemon = True
p.start()
p.join() # wait for subprocess to terminate
print('end')
Il gestore redirect_stdout
contesto in Python 3.4 rende afferrando stdout facile (in questo caso).
from contextlib import redirect_stdout
from sys import stdout
from tempfile import TemporaryFile
with TemporaryFile(mode='w+', encoding=stdout.encoding) as buf:
with redirect_stdout(buf):
output() # the function defined above
buf.seek(0)
s = buf.read()
print('output from TemporaryFile:')
print(s)
posso poi semplicemente chiamare lo script per ottenere il seguente risultato:
$ python stackoverflow.py
output from TemporaryFile:
redirected
forked output
end
Questo è esattamente quello che voglio, e funziona bene.
La mia confusione deriva dal fatto che se io se cambio TemporaryFile
con TextIOWrapper
, il comportamento del mio script cambia.
from io import BytesIO, TextIOWrapper
with TextIOWrapper(BytesIO(), stdout.encoding) as buf:
with redirect_stdout(buf):
output() # the function defined at the start
buf.seek(0)
s = buf.read()
print('output from TextIO:')
print(s)
Ora quando chiamo il programma, perdo l'output dal processo biforcuto.
$ python stackoverflow.py
output from TextIO:
redirected
end
Cosa sta succedendo?
ho il sospetto che il problema ha a che fare con il fatto che l'oggetto TextIOWrapper
non ha un descrittore di file, e che os.fork()
(usato da multiprocessing
) può quindi essere la sostituzione del TextIOWrapper
con un altro, ma ammetto po 'di confusione c'è (soprattutto considerando che lo stdout sembra essere un TextIOWrapper
confileno()
implementato).
>>> from sys import stdout
>>> stdout.fileno()
1
>>> stdout
<_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
Grazie per qualsiasi informazione.
Credo che tu sia sulla strada giusta. Non ho abbastanza per pubblicare una risposta, ma penso che sia un problema con i descrittori di file; sys.stdout ha un descrittore a livello di sistema, mentre TextIOWrapper è interno a Python. – Cyphase
@Cyphase Sono quasi sicuro che tu abbia ragione. Il reindirizzamento di 'stdout',' stderr' o 'stdin' è un'operazione a livello di sistema operativo, non un'operazione di python. Funziona su descrittori di file. Un oggetto 'BytesIO' non ha descrittore di file perché è strettamente un blob di byte in memoria. 'TemporaryFile' è la strada da percorrere. Su Linux se crei il file nella directory '/ dev/shm', non colpisce mai un disco effettivamente (anche se, probabilmente, [non si usa'/tmp'] (http://stackoverflow.com/questions/9745281/tmp-vs-dev-SHM-per-temp-file-storage on-linux)). – eestrada