在Python中捕获同一进程的stdout

7 投票
4 回答
5979 浏览
提问于 2025-04-15 21:41

我有一个Python脚本,它会调用很多函数,每个函数都会把结果输出到标准输出(也就是屏幕上)。有时候我运行这个脚本的时候,希望把这些输出内容通过电子邮件发送出去,同时还想附上一个生成的文件。我想知道怎么能把这些输出内容先存到内存里,这样我就可以用email模块来构建电子邮件。

到目前为止,我的想法有:

  • 使用内存映射文件(但这似乎需要在硬盘上预留空间,而我不知道输出内容会有多长)
  • 绕过这些步骤,直接把输出通过管道发送到sendmail(但如果我还想附加文件,这可能会比较麻烦)

4 个回答

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

你提到你的脚本“调用了一堆函数”,所以我猜这些函数是你程序里可以用的Python函数。我还猜测你在这些函数里用print来输出结果。如果是这样的话,你可以把sys.stdout换成StringIO.StringIO,这样就能拦截你写的所有内容。然后你可以调用StringIO.getValue方法,获取所有发送到输出通道的内容。这种方法也适用于使用subprocess模块的外部程序,它们会写入sys.stdout

这是一种简单的方法。不过我建议你使用logging模块来输出内容。这样你会对输出的方式有更多的控制,而且管理起来也更方便。

撰写回答