it-swarm.com.de

Wie erfasse ich die stdout-Ausgabe eines Python Funktionsaufrufs?

Ich verwende eine Python Bibliothek, die etwas mit einem Objekt macht

do_something(my_object)

und ändert es. Dabei werden einige Statistiken nach stdout gedruckt, und ich möchte diese Informationen in den Griff bekommen. Die richtige Lösung wäre, do_something() zu ändern, um die relevanten Informationen zurückzugeben.

out = do_something(my_object)

aber es wird eine Weile dauern, bis die Entwickler von do_something() zu diesem Thema gelangen. Als Workaround habe ich darüber nachgedacht, alles, was do_something() in stdout schreibt, zu analysieren.

Wie kann ich eine Standardausgabe zwischen zwei Punkten im Code erfassen, z.

start_capturing()
do_something(my_object)
out = end_capturing()

?

86
Nico Schlömer

Versuchen Sie diesen Kontextmanager:

# import StringIO for Python 2 or 3
try:
    from StringIO import StringIO
except ImportError:
    from io import StringIO

import sys

class Capturing(list):
    def __enter__(self):
        self._stdout = sys.stdout
        sys.stdout = self._stringio = StringIO()
        return self
    def __exit__(self, *args):
        self.extend(self._stringio.getvalue().splitlines())
        del self._stringio    # free up some memory
        sys.stdout = self._stdout

Verwendung:

with Capturing() as output:
    do_something(my_object)

output ist jetzt eine Liste mit den vom Funktionsaufruf ausgedruckten Zeilen.

Fortgeschrittene Nutzung:

Was möglicherweise nicht offensichtlich ist, ist, dass dies mehrmals durchgeführt werden kann und die Ergebnisse verkettet werden:

with Capturing() as output:
    print 'hello world'

print 'displays on screen'

with Capturing(output) as output:  # note the constructor argument
    print 'hello world2'

print 'done'
print 'output:', output

Ausgabe:

displays on screen                     
done                                   
output: ['hello world', 'hello world2']

Update : Sie haben redirect_stdout() zu contextlib in Python 3.4 (zusammen mit redirect_stderr()). Sie könnten also io.StringIO Verwenden, um ein ähnliches Ergebnis zu erzielen (obwohl Capturing sowohl eine Liste als auch ein Kontext ist Manager ist wohl bequemer).

147
kindall

In python> = 3.4 enthält contextlib ein redirect_stdout Dekorateur. Es kann verwendet werden, um Ihre Frage wie folgt zu beantworten:

import io
from contextlib import redirect_stdout

f = io.StringIO()
with redirect_stdout(f):
    do_something(my_object)
out = f.getvalue()

Von den Dokumenten :

Kontextmanager zum vorübergehenden Umleiten von sys.stdout in eine andere Datei oder ein dateiähnliches Objekt.

Dieses Tool erweitert vorhandene Funktionen oder Klassen, deren Ausgabe auf Standardausgabe festgelegt ist, um zusätzliche Flexibilität.

Beispielsweise wird die Ausgabe von help () normalerweise an sys.stdout gesendet. Sie können diese Ausgabe in einer Zeichenfolge erfassen, indem Sie die Ausgabe an ein io.StringIO-Objekt umleiten:

  f = io.StringIO() 
  with redirect_stdout(f):
      help(pow) 
  s = f.getvalue()

Um die Ausgabe von help () an eine Datei auf der Festplatte zu senden, leiten Sie die Ausgabe in eine reguläre Datei um:

 with open('help.txt', 'w') as f:
     with redirect_stdout(f):
         help(pow)

So senden Sie die Ausgabe von help () an sys.stderr:

with redirect_stdout(sys.stderr):
    help(pow)

Beachten Sie, dass der globale Nebeneffekt von sys.stdout bedeutet, dass dieser Kontextmanager nicht für die Verwendung in Bibliothekscode und den meisten Thread-Anwendungen geeignet ist. Es hat auch keine Auswirkung auf die Ausgabe von Unterprozessen. Für viele Hilfsskripte ist dies jedoch immer noch eine nützliche Methode.

Dieser Kontextmanager ist wiedereintrittsfähig ("reentrant").

62
ForeverWintr