2013-05-15 15 views
59

używam biblioteka Pythona, który robi coś do obiektuJak przechwycić wyjście standardowe z wywołania funkcji Pythona?

do_something(my_object) 

i zmienia go. Robiąc to, wypisuje niektóre statystyki na standardowe wyjście, a ja chciałbym opanować te informacje. Właściwym rozwiązaniem byłoby zmienić do_something() wrócić istotnych informacji,

out = do_something(my_object) 

ale to będzie trochę czasu, zanim deweloperów z do_something() dostać się do tej kwestii. W celu obejścia tego problemu pomyślałem o przeanalizowaniu tego, co do_something() zapisuje na standardowe wyjście.

Jak mogę przechwycić wyjście stdout między dwoma punktami w kodzie np

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

?

+2

możliwe duplikat [przechwytywanie dis.dis wyniki] (http://stackoverflow.com/questions/12111717/capturing-dis-dis-results) –

+0

Moja odpowiedź na pytanie dotyczy połączonego również tutaj. –

+0

Próbowałem to zrobić raz, a najlepszą odpowiedzią znalazłem: http://stackoverflow.com/a/3113913/1330293 – elyase

Odpowiedz

115

Spróbuj menedżera kontekstowego:

from cStringIO 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 

Zastosowanie:

with Capturing() as output: 
    do_something(my_object) 

output jest lista zawierająca wiersze drukowane przez wywołanie funkcji.

Zaawansowane użycie:

Co może nie być oczywiste jest to, że można zrobić więcej niż jeden raz, a wyniki łączone:

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 

wyjściowa:

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

+1 To jest kewl, uprzejmie. – martineau

+0

Dzięki! I dziękuję za dodanie zaawansowanej sekcji ... Początkowo użyłem przypisania plasterka, aby przykleić przechwycony tekst do listy, a potem poczułem się w głowie i użyłem '.extend()' zamiast tego, aby mogło być użyte w sposób konkatenatywny, tak jak zauważyłeś. :-) – kindall

+0

Nie ma za co - cieszę się, że nie miałeś nic przeciwko mojej edycji. – martineau

27

W python> = 3.4, contextlib zawiera dekorator redirect_stdout. Można go stosować, aby odpowiedzieć na Twoje pytanie tak:

import io 
from contextlib import redirect_stdout 

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

Od the docs:

kierownik kontekst dla tymczasowo przekierowanie sys.stdout do innego pliku lub obiektu plikopodobny.

To narzędzie dodaje elastyczności istniejącym funkcjom lub klasom, dla których wyjście jest podłączone do stdout.

Na przykład wyjście help() zwykle jest wysyłane do sys.stdout. Możesz może przechwycić to wyjście w ciągu, przekierowując wyjście do io.StringIO obiektu:

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

Aby wysłać wyjście pomocy() w pliku na dysku, przekierować wyjście do regularny plik:

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

Aby wysłać wyjście pomocy() do sys .stderr:

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

Należy zauważyć, że globalny efekt uboczny na sys.stdout oznacza, że ​​ten kontekst menedżer nie nadaje się do użycia w kodzie biblioteki i najbardziej gwintowany aplikacji. Nie ma również wpływu na wynik podprocesów. Jednak nadal jest to przydatne podejście do wielu skryptów narzędziowych.

Ten menedżer kontekstu jest ponownie wyświetlany.

Powiązane problemy