Как захватить вывод stdout из вызова функции Python?

Я использую библиотеку Python, которая что-то делает с объектом

do_something(my_object)

и изменяет его. При этом он печатает некоторую статистику в stdout, и я хотел бы получить эту информацию. Правильным решением было бы изменить do_something() чтобы вернуть соответствующую информацию,

out = do_something(my_object)

но это будет некоторое время до разработчиков do_something() перейти к этой проблеме. В качестве обходного пути я подумал о разборе whatever do_something() пишет в stdout.

как может Я фиксирую вывод stdout между двумя точками кода, например,

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

?

2 ответов


попробуйте этот менеджер контекста:

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

использование:

with Capturing() as output:
    do_something(my_object)

output теперь это список, содержащий строки, напечатанные вызовом функции.

дополнительные функции:

что может быть не очевидно, так это то, что это может быть сделано более одного раза и результаты объединены:

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

выход:

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

обновление: они добавил redirect_stdout() to contextlib в Python 3.4 (вместе с redirect_stderr()). Так что вы могли бы использовать io.StringIO С тем, чтобы достичь аналогичного результата (хотя Capturing быть списком, а также контекстным менеджером, возможно, более удобно).


в python >= 3.4 contextlib содержит redirect_stdout декоратор. Его можно использовать, чтобы ответить на ваш вопрос так:

import io
from contextlib import redirect_stdout

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

С документы:

Context manager для временного перенаправления sys.стандартный вывод в другой файл или файлоподобный объект.

этот инструмент добавляет гибкость к существующим функциям или классам, выход подключен к stdout.

например, вывод help () обычно отправляется в sys.стандартный вывод. Вы может захватывать этот вывод в строке, перенаправляя вывод на Ио.StringIO объекта:

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

чтобы отправить вывод help() в файл на диске, перенаправьте вывод на обычный файл:

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

для отправки вывода help () в sys.поток stderr:

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

обратите внимание, что глобальный побочный эффект на sys.stdout означает, что этот контекст менеджер не подходит для использования в коде библиотеки и большинстве потоков приложения. Он также не влияет на выходные данные подпроцессов. Тем не менее, это по-прежнему полезный подход для многих сценариев утилит.

этот контекстный менеджер является реентерабельным.