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


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

do_something(my_object)

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

out = do_something(my_object)

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

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

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

?

2 66

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() до 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()

С документы:

контекстный менеджер для временного перенаправления 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.стандартный вывод означает, что в этом контексте менеджер не подходит для использования в коде библиотеки и наиболее резьбовой приложения. Это также не влияет на выход подпроцессов. Тем не менее, это все еще полезный подход для многих сценариев утилит.

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