Python封装一个函数以将输出打印到变量中

3
如果我有一个包含大量打印语句的函数:
例如:
def funA():
  print "Hi"
  print "There"
  print "Friend"
  print "!"

我想要做的是类似于这样的事情。
def main():
  ##funA() does not print to screen here
  a = getPrint(funA()) ##where getPrint is some made up function/object
  print a ##prints what funA would normally print at this step

当funcA被调用时,它不会打印任何内容,而是将结果输出到一个对象中。我之后会打印这个对象来获取结果。有没有一种方法可以实现这个功能?同时我也不想修改原始函数。

希望我的解释清晰明了。


3
相关链接:https://dev59.com/8XM_5IYBdhLWcg3wzmnL - jldupont
6个回答

8

只要你不介意微小的语法差异,你几乎可以做到你想做的任何事情:

import cStringIO
import sys

def getPrint(thefun, *a, **k):
  savstdout = sys.stdout
  sys.stdout = cStringIO.StringIO()
  try:
    thefun(*a, **k)
  finally:
    v = sys.stdout.getvalue()
    sys.stdout = savstdout
  return v

唯一的区别是,您必须调用 getPrint(funA),而不是 getPrint(funA())。也就是说,您必须传递函数对象本身,不要带上立即调用它的括号,在getPrint执行其操作之前,之前

如果您坚持要使用这些额外的括号,则getPrint无法完成所有所需的准备工作,并且必须通过其他代码来补充以正确准备事物(我强烈建议去掉额外的括号,从而实现将所有功能封装在getPrint内部!)。


+1. 我会使用sys.__stdout__,它正式包含原始的sys.stdout。如果我没记错的话,就不需要将原始的sys.stdout保存在savstdout中。 - Eric O. Lebigot
如果您在IDLE或其他基于GUI的IDE下运行代码,则“原始stdout”可能无用或无法使用(例如,它可能已关闭,指向不存在的终端等);当getPrint不再存在时,确实需要保存和恢复sys.stdout以使IDE恢复可用状态。 - Alex Martelli
1
你为什么要调用cStringIO模块? - Roger Pate

3
from cStringIO import StringIO

def getPrint(func, *args, **kwds):
  old_stdout = sys.stdout
  sys.stdout = StringIO()
  try:
    func(*args, **kwds)
  except:
    raise
  else:
    return sys.stdout.getvalue()
  finally:
    sys.stdout = old_stdout

#...
a = getPrint(funA) # notice no (), it is called by getPrint
print a.rstrip("\n") # avoid extra trailing lines

2

最好的方法是使用上下文管理器

from contextlib import contextmanager
import StringIO
import sys

@contextmanager
def capture():
    old_stdout = sys.stdout
    sys.stdout = StringIO.StringIO()
    try:
        yield sys.stdout
    finally:
        sys.stdout = old_stdout

现在您可以运行任何打印代码:

with capture() as c:
    funA()
    funB()
    print 'HELLO!'

稍后:
print c.getvalue()

1

使用 cStringIO(请参见doc)。

from cStringIO import StringIO

old_stdout = sys.stdout
sys.stdout = mystdout = StringIO()

getPrint( funA() )
# use mystdout to get string

1

0

最简单的方法是将您的funA()更改为不打印任何内容,而只返回字符串值。

像这样:

def funA():
    return "Hi\n" + "There\n" + "Friend\n" + "!\n"

# later:
print(funA())

收集字符串并打印它们总是很容易的;但是在字符串被打印时收集它们就比较棘手了。

如果你有一个庞大的现有打印函数库,那么可以使用这里提供的技巧之一来收集输出。


问题在于该函数不像我发布的那个那样简单。它调用其他函数,这些函数又调用其他函数来进行打印。 - John Jiang
好的,你有两个选择。如果所有函数都使用一个共同的单一函数来发出它们的输出,那么挂钩那个函数,你就可以捕获所有的输出;否则(也许它们都使用 Python 2.x 的 print statement,你无法真正挂钩),那么你将想要使用此页面上记录的其中一种技巧。 - steveha

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