在实时python中捕获函数的输出

时间:2014-10-14 17:11:06

标签: python-2.7 output real-time capture sympy

我找不到我想要的东西。

我想实时从python函数中获取输出(stdout)。

实际问题是我想在我的UI中使用进度条绘制图表(使用来自sympy的cplot)。参数verbose使cplot输出到stdout的进度。

sympy.mpmath.cplot(lambda z: z, real, imag, verbose=True)

输出类似于:

0 of 71
1 of 71
2 of 71
...

等等。

我想逐行捕捉,以便我可以制作进度条。 (我意识到如果不实现多线程,这可能是不可能的)。我正在使用python2.7(主要是因为我需要不在python3中的库)

所以,¿我如何实现这一目标?

2 个答案:

答案 0 :(得分:0)

您可以通过monkeypatching sys.stdout捕获标准输出。执行此操作的一种好方法是使用上下文管理器,以便在完成后将其放回(即使代码引发异常)。如果您不使用上下文管理器,请务必使用sys.stdout块将原始finally放回原位。

你需要一个类似文件的对象,它接受输入并用它做你想做的事。子类化StringIO是一个好的开始。这是一个上下文管理器的示例,它捕获stdout和stderr并将它们放在绑定变量的结果中。

class CapturedText(object):
    pass

@contextmanager
def captured(disallow_stderr=True):
    """
    Context manager to capture the printed output of the code in the with block

    Bind the context manager to a variable using `as` and the result will be
    in the stdout property.

    >>> from tests.helpers import capture
    >>> with captured() as c:
    ...     print('hello world!')
    ...
    >>> c.stdout
    'hello world!\n'
    """
    import sys

    stdout = sys.stdout
    stderr = sys.stderr
    sys.stdout = outfile = StringIO()
    sys.stderr = errfile = StringIO()
    c = CapturedText()
    yield c
    c.stdout = outfile.getvalue()
    c.stderr = errfile.getvalue()
    sys.stdout = stdout
    sys.stderr = stderr
    if disallow_stderr and c.stderr:
        raise Exception("Got stderr output: %s" % c.stderr)

source

它的工作原理如docstring所示。您可以将StringIO()替换为您自己编写进度条的类。

答案 1 :(得分:0)

另一种可能性是monkeypatch sympy.mpmath.visualization.print,因为cplot使用print来打印输出,并使用from __future__ import print_function

首先,如果您没有使用Python 3,请确保使用from __future__ import print_function,否则这将是一个SyntaxError。

然后像

def progressbar_print(*args, **kwargs):
    # Take *args and convert it to a progress output
    progress(*args)
    # If you want to still print the output, do it here
    print(*args, **kwargs)

sympy.mpmath.visualization.print = progressbar_print

您可能希望在将其放回的自定义函数中对其进行monkeypatch,因为该模块中的其他函数也可能使用print。同样,请记住使用上下文管理器或finally块来执行此操作,以便即使引发异常也会将其放回。

Monkeypatching sys.stdout绝对是更为标准的做法,但我喜欢这个解决方案,因为它表明将print作为一个函数实际上可以是有用的。