如何在Python中重定向函数的打印输出

8
我有一个在Python中打印标准输出的函数。可能是重复问题:
我是否能将Python中的stdout重定向到某种字符串缓冲区中?
def foo():
    print("some text")

我希望“重定向”此函数中打印的文本到一个变量中,即“包装”此函数或其他操作以便将文本存储在变量中:
text = wrapper(foo)

有没有一种强大的方法暂时更改 sys.stdout,或者将变量作为 FileObject 打开,或者其他什么方法?

为什么不直接使用您自己的打印函数呢? - phant0m
1
我们是否假设您无法修改函数,只需将打印更改为“返回”?并且您希望在函数期间(即装饰它)暂时修改sys.stdout以捕获它? - Jon Clements
看一下这个重复问题-它提供了将sys.stdout重定向到StringIO对象的解决方案。 - David Robinson
Python 2 还是 Python 3?在 Python 3 中,你可以重新定义 print... - l4mpi
@David:我认为你指出的链接就是我需要的。谢谢。 - Alex
显示剩余3条评论
2个回答

21

对于Python3.4及以上版本,标准库中提供了一个上下文管理器来实现此功能。

with contextlib.redirect_stdout(file_like_object):
    ...

这个答案的一部分已经更新,但主要是针对仍然停留在python2.x世界中的人

如果您被困在较旧版本的Python上,编写此上下文管理器并不太难。关键是您可以将sys.stdout更新为任何文件类似对象(这就是print写入的内容):

>>> import sys
>>> import StringIO
>>> stdout = sys.stdout  # keep a handle on the real standard output
>>> sys.stdout = StringIO.StringIO() # Choose a file-like object to write to
>>> foo() 
>>> sys.stdout = stdout
>>> foo()
bar

为了创建一个上下文管理器,在进入上下文时将stdout设置为您想要的任何内容,然后在退出上下文时重置stdout。

这里有一个使用contextlib创建上下文管理器的简单示例:

import contextlib
import sys

@contextlib.contextmanager
def stdout_redirect(where):
    sys.stdout = where
    try:
        yield where
    finally:
        sys.stdout = sys.__stdout__

def foo():
    print 'bar'

# Examples with StringIO
import StringIO

with stdout_redirect(StringIO.StringIO()) as new_stdout:
    foo()

new_stdout.seek(0)
print "data from new_stdout:",new_stdout.read()

new_stdout1 = StringIO.StringIO()
with stdout_redirect(new_stdout1):
    foo()

new_stdout1.seek(0)
print "data from new_stdout1:",new_stdout1.read()

# Now with a file object:
with open('new_stdout') as f:
    with stdout_redirect(f):
        foo()

# Just to prove that we actually did put stdout back as we were supposed to
print "Now calling foo without context"
foo()

注意:
在Python3.x中,StringIO.StringIO已经移动到io.StringIO。此外,在Python2.x中,cStringIO.StringIO可能略微更加高效。

3
+1 对于上下文管理器建议的赞同,这可能是最清晰的方法。 - l4mpi
@l4mpi:请参考PEP 0343中的“临时重定向stdout”部分。那里还有其他一些可能会引起您兴趣的示例。 - martineau
1
从Python 3.4开始,contextlib.redirect_stdout()也可用。 - alec_djinn
这是一个针对使用Python 3.X的人们的答案,因为上面的方法对我来说不起作用。 - pyCthon

7
在Python 3.x中,您只需要重新定义print即可。
B = []

def print(str):
    global B
    B.append(str)

def A():
    print("example")

A()

>>> B
['example']

如果出于某些原因,您需要重新启用内置打印功能,请执行以下操作:

from builtins import print

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