同时捕获并显示控制台功能输出

时间:2017-01-10 21:57:41

标签: python python-3.x

现在我用它来捕获Python函数的输出并将其存储在变量中:

import io
from contextlib import redirect_stdout

def catch_output(func):
    result = io.StringIO()
    with redirect_stdout(result):
        func()
    return result.getvalue()

output = catch_output(my_func)

这样可以正常工作,但它也会在func调用完成之前将控制台静音。 有没有人知道我是否可以将func的 live 输出写入/管道输出到控制台并同时将其存储在变量中?

3 个答案:

答案 0 :(得分:1)

根据我所做的评论中的建议和示例将我们的函数转换为线程,以便我们可以定期检查该函数的输出并将其复制到真正的标准输出。

import sys
import time
import threading
from cStringIO import StringIO

def foo(n):
    for x in range(n):
        time.sleep(1) #intense computation
        print('test: {}'.format(n))


#i'm using python 2.7 so I don't have contextlib.redirect_stdout
realstdout = sys.stdout
sys.stdout = StringIO()

t = threading.Thread(target=foo, args=(10,))
t.start()

lastpos = 0 #last cursor position in file

while True:
    t.join(.1) #wait .1 sec for thread to complete

    if sys.stdout.tell() != lastpos: #data has been written to stdout
        sys.stdout.seek(lastpos) #go back to our last position
        realstdout.write(sys.stdout.read()) #read the data to the real stdout
        lastpos = sys.stdout.tell() #update lastpos

    if not t.is_alive(): #when we're done
        break

sys.stdout.seek(0) #seek back to beginning of file
output = sys.stdout.read() #copy to a usable variable
sys.stdout = realstdout #reset stdout

答案 1 :(得分:1)

您可以将stdout重定向到自定义文件类对象,该对象将写入转发到多个文件:

import contextlib
import io
import sys


class TeeIO:
    def __init__(self, original, target):
        self.original = original
        self.target = target

    def write(self, b):
        self.original.write(b)
        self.target.write(b)


@contextlib.contextmanager
def tee_stdout(target):
    tee = TeeIO(sys.stdout, target)
    with contextlib.redirect_stdout(tee):
        yield


buf = io.StringIO()
with tee_stdout(buf):
    print("foo")
print(buf.getvalue())

答案 2 :(得分:0)

这是我最终使用的。我以为我把这个留给了那些与我一样很难上课和上课的人。

import sys
import io
from contextlib import redirect_stdout


def get_multi_writer(streams):
    writer = type('obj', (object,), {})
    writer.write = lambda s: [stream.write(s) for stream in streams]
    return writer


def catch_output(func, args, kwargs):
    streams = [sys.stdout, io.StringIO()]
    with redirect_stdout(get_multi_writer(streams)):
        func(*args, **kwargs)
    return streams[1].getvalue()


print(catch_output(my_func, [], {}))