Capture the output from function in real time python

吃可爱长大的小学妹 提交于 2020-07-19 11:15:26

问题


I didn't find quite what I was looking for.

I want to obtain the output (stdout) from a python function in real time.

The actual problem is that I want to plot a graph (with cplot from sympy) with a progress bar in my UI. The argument verbose makes cplot output the progress to stdout.

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

The output would be something like:

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

And so on.

I want to capture line by line so I can make a progress bar. (I realize this might not be possible without implementing multithreading). I'm using python2.7 (mainly because I need libraries that aren't in python3)

So, ¿How do I achieve that?


回答1:


You can capture stdout by monkeypatching sys.stdout. A good way to do it is using a context manager, so that it gets put back when you are done (even if the code raises an exception). If you don't use a context manager, be sure to put the original sys.stdout back using a finally block.

You'll need an object that is file-like, that takes the input and does what you want with it. Subclassing StringIO is a good start. Here's an example of a context manager that captures stdout and stderr and puts them in the result of the bound variable.

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)

It works as shown in the docstring. You can replace StringIO() with your own class that writes the progress bar.




回答2:


Another possibility would be to monkeypatch sympy.mpmath.visualization.print, since cplot uses print to print the output, and it uses from __future__ import print_function.

First, make sure you are using from __future__ import print_function if you aren't using Python 3, as this will otherwise be a SyntaxError.

Then something like

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

You might want to monkeypatch it in a custom function that puts it back, as other functions in that module might use print as well. Again, remember to do this using either a context manager or a finally block so that it gets put back even if an exception is raised.

Monkeypatching sys.stdout is definitely the more standard way of doing this, but I like this solution in that it shows that having print as a function can actually be useful.



来源:https://stackoverflow.com/questions/26366406/capture-the-output-from-function-in-real-time-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!