Захват стандартного вывода в том же процессе в Python - PullRequest
6 голосов
/ 16 апреля 2010

У меня есть скрипт на python, который вызывает несколько функций, каждая из которых записывает вывод в stdout. Иногда, когда я запускаю его, я хотел бы отправить вывод по электронной почте (вместе с сгенерированным файлом). Я хотел бы знать, как я могу записать вывод в память, чтобы я мог использовать модуль email для создания электронной почты.

Мои идеи до сих пор были:

  • использовать файл с отображением в памяти (но похоже, что для этого мне нужно зарезервировать место на диске, и я не знаю, как долго будет вывод)
  • обойти все это и направить вывод в sendmail (но это может быть сложно, если я также хочу прикрепить файл)

Ответы [ 4 ]

13 голосов
/ 25 июня 2010

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

import sys, StringIO, contextlib

class Data(object):
    pass

@contextlib.contextmanager
def capture_stdout():
    old = sys.stdout
    capturer = StringIO.StringIO()
    sys.stdout = capturer
    data = Data()
    yield data
    sys.stdout = old
    data.result = capturer.getvalue()

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

with capture_stdout() as capture:
    print 'Hello'
    print 'Goodbye'
assert capture.result == 'Hello\nGoodbye\n'
7 голосов
/ 17 апреля 2010

Довольно просто захватить вывод.

import sys, StringIO
old_stdout = sys.stdout
capturer = StringIO.StringIO()
sys.stdout = capturer
#call functions
print "Hi"
#end functions
sys.stdout = old_stdout
output = capturer.getvalue()
3 голосов
/ 16 апреля 2010

Вы сказали, что ваш скрипт "вызывает кучу функций", поэтому я предполагаю, что они являются функциями python, доступными из вашей программы. Я также предполагаю, что вы используете print для генерации вывода во всех этих функциях. Если это так, вы можете просто заменить sys.stdout на StringIO.StringIO, который будет перехватывать все, что вы пишете. Затем вы можете наконец вызвать метод .getValue на вашем StringIO, чтобы получить все, что было отправлено на выходной канал. Это также будет работать для внешних программ, использующих модуль подпроцесса, которые записывают в sys.stdout.

Это дешевый способ. Я бы порекомендовал вам сделать вывод, используя модуль logging. У вас будет намного больше контроля над тем, как он выводит данные, а также вы можете управлять им проще.

1 голос
/ 24 мая 2016

И я изменил ответ Гари Робинсона, чтобы убедиться, что stdout всегда восстанавливается, даже если есть исключение:

import sys, StringIO, contextlib

class Data(object):
    pass

@contextlib.contextmanager
def capture_stdout():
    old = sys.stdout
    capturer = StringIO.StringIO()
    data = Data()
    try:
        sys.stdout = capturer
        yield data
    finally:
        sys.stdout = old
        data.result = capturer.getvalue()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...