Ich versuche, die Dinge, die auf STDERR gedruckt werden, zu erfassen, wenn ich Befehle in jupyter Notebook ausführen. Insbesondere verwende ich TensorFlow, das fprintf
von den C-Teilen ausgibt, das normalerweise auf der Konsole gedruckt wird, aber ich möchte in die Python-Variable speichern.
Ich habe FDRedirector aus der IPython-Codebasis verwendet, die setzt up os.pipe
, um die Ausgabe in Python-String zu erfassen.
Das Problem mit diesem Code ist jedoch, dass der Kernel für eine ausreichend große Ausgabe hängen bleibt. Ich vermute, dass es für die Ausgabe über 65k hängt, da das die Pipe-Puffergröße unter Linux ist und gdb
zeigt, dass der Hang in write
passiert. Hat jemand eine Lösung, die mit größeren Ausgängen arbeiten würde?
Als Beispiel für das, was ich gerade mache, benutze FDRedirector
%Vor% Am Ende enthält "captured_stderr" alle Dinge, die in stderr gedruckt wurden, einschließlich longstringlongstring
. Wenn Sie longstring
part viel länger machen (& gt; 100k), wird dies einfrieren.
Sie können versuchen, Ihre Ausgabe in eine temporäre Datei zu leiten - also keine Pufferbeschränkungen:
%Vor%Bitte lassen Sie mich wissen, ob dies für Ihren Zweck funktioniert. Leider habe ich TF nicht installiert.
Jupyter selbst überlebte die Ausgabe von 1 Mb zu einer Zelle:)
Das Problem mit FDRedirector
ist, dass es nur einmal aus der Pipe gelesen wird. Da sowohl der Hersteller als auch das Verbraucherende der Leitung in demselben Prozess leben, wird dies das Schreibende der Leitung blockieren, sobald der Puffer voll ist. Die Lösung besteht darin, kontinuierlich vom Leseende zu lesen, um die andere Seite nicht zu blockieren. Eine Möglichkeit besteht darin, einen Consumer-Thread zu erstellen.
Hier ist ein Stück Code, der genau das tut: stderr zu einer Pipe umleiten und kontinuierlich mit einem Thread lesen.
Update : Der Code ist jetzt für Python 3, wie von OPs Kommentar vorgeschlagen. Angenommen, Sie möchten die erfasste Ausgabe in einer Python 3-Zeichenkette (d. H. Einer Unicode-Zeichenkette) haben, konvertiert redirect
nun die gelesenen Bytes in eine Zeichenkette. Dafür akzeptiert sie encoding
und errors
Argumente - genau wie Pythons decode
(und dieselben Standardwerte verwendend). Dies löst ein echtes Problem für den allgemeinen Anwendungsfall: Wenn Sie auf die erfassten Daten als String für die weitere Verarbeitung zugreifen möchten, müssen Sie wissen, in welche Kodierung stderr geschrieben wird. Dies gilt auch für die Vorgehensweise in der anderen Antwort, bei der der Stream in eine Datei umgeleitet wird. Wenn nur die Bytes in Ordnung sind, können Sie den Code ändern, um ein io.BytesIO
zu verwenden.
Der redirect
-Kontextmanager kann dann verwendet werden, um jeden Strom zeitweilig in einen internen Puffer umzuleiten. Beachten Sie, dass unter% jc_% sys.stderr
nicht mit STDERR
verbunden ist, es ist ein ipykernel.iostream.OutStream
-Objekt, das ein Python file
emuliert. Also müssen wir os.write
auf STDERR
setzen, um die Umleitung zu sehen.
Dieser Code versucht, Jupyter %%capture
magic zu imitieren, indem er eine IPython.utils.capture.CapturedIO
-Instanz zurückgibt.
Er verwendet tempfile.TemporaryFile
, um die in stdout
und stderr
geschriebenen Bytes zu speichern. Die Methode __init__
stellt sicher, dass sys.stdout
identisch mit sys.__stdout__
im Block with
ist. Genauso verhält es sich mit sys.stderr
. Die __exit__
-Methode synchronisiert zuerst Daten mit den temporären Dateien mit os.fdatasync
, liest dann Bytes aus temporären Dateien und schreibt sie zurück in StringIO
instance.
Die zurückgegebene IPython.utils.capture.CapturedIO
instanz sport stdout
, stderr
Eigenschaft, eine show
Methode und selbst ist aufrufbar.
Test;
%Vor%Ausgabe;
%Vor%