在Python中捕获同一进程中的stdout

7
我有一个调用一堆函数的Python脚本,每个函数都会将输出写入标准输出。有时候我想把输出和生成的文件一起发送到电子邮件中。我想知道如何在内存中捕获输出,以便可以使用email模块来构建电子邮件。
目前我的想法有:
  • 使用内存映射文件(但这似乎需要在磁盘上保留空间,而且我不知道输出的长度)
  • 跳过所有这些,将输出管道传输到sendmail(但如果我还想附加文件,则可能很困难)
4个回答

14

我修改了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'

8

捕获输出非常简单。

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

4
你说你的脚本“调用了一堆函数”,所以我假设它们是你程序中可访问的Python函数。我还假设你在所有这些函数中使用print生成输出。如果是这样的话,你可以用StringIO.StringIO替换sys.stdout,它将拦截你写入的所有东西。然后,你最终可以调用StringIO的.getValue方法,以获取发送到输出通道的所有内容。这也适用于使用subprocess模块写入sys.stdout的外部程序。
这是一种廉价的方法。我建议你使用logging模块进行输出。你将更好地控制它的输出,并且可以更轻松地控制它。

1
谢谢。现在便宜的应该可以。如果我要使用日志记录,我该如何构建电子邮件(记住还有一个要附加的文件)? - danben
1
+1 for logging module,print语句的功能非常有限。 - Alexander Lebedev
1
不客气。使用smtpmail包可以创建一个简单的文本邮件。如果需要添加附件,您需要使用email包中的工具对附件进行mime编码,然后将其附加到电子邮件中。最后使用smptmail发送即可。这里有一些示例:http://docs.python.org/library/email-examples.html - Noufal Ibrahim
1
关于获取您记录的内容,您可以简单地创建一个EmailHandler并将其添加到您的记录器中,它将保存您正在记录的内容,以便稍后获取、格式化和发送。 - Noufal Ibrahim

3

我修改了Gary Robinson的答案,以确保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()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接