首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何从Python函数调用中捕获stdout输出?

如何从Python函数调用中捕获stdout输出?
EN

Stack Overflow用户
提问于 2013-05-16 01:13:30
回答 4查看 78.8K关注 0票数 156

我使用的是Python库,它对对象执行某些操作

代码语言:javascript
复制
do_something(my_object)

并改变它。在执行此操作时,它会将一些统计数据打印到stdout,我希望能够掌握这些信息。正确的解决方案是更改do_something()以返回相关信息,

代码语言:javascript
复制
out = do_something(my_object)

do_something()的开发者还需要一段时间才能解决这个问题。作为一种变通方法,我考虑解析do_something()写入标准输出的任何内容。

如何捕获代码中两点之间的标准输出,例如,

代码语言:javascript
复制
start_capturing()
do_something(my_object)
out = end_capturing()
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2013-05-16 01:43:40

尝试此上下文管理器:

代码语言:javascript
复制
from io import StringIO 
import sys

class Capturing(list):
    def __enter__(self):
        self._stdout = sys.stdout
        sys.stdout = self._stringio = StringIO()
        return self
    def __exit__(self, *args):
        self.extend(self._stringio.getvalue().splitlines())
        del self._stringio    # free up some memory
        sys.stdout = self._stdout

用法:

代码语言:javascript
复制
with Capturing() as output:
    do_something(my_object)

output现在是一个列表,其中包含由函数调用打印的行。

高级用法:

可能不明显的是,可以多次执行此操作,并将结果连接在一起:

代码语言:javascript
复制
with Capturing() as output:
    print('hello world')

print('displays on screen')

with Capturing(output) as output:  # note the constructor argument
    print('hello world2')

print('done')
print('output:', output)

输出:

代码语言:javascript
复制
displays on screen                     
done                                   
output: ['hello world', 'hello world2']

更新:他们在Python3.4的contextlib中添加了redirect_stdout() (以及redirect_stderr())。因此,您可以结合使用io.StringIO来实现类似的结果(尽管Capturing既是一个列表,也是一个上下文管理器,可以说更方便)。

票数 230
EN

Stack Overflow用户

发布于 2020-06-16 05:28:52

这是一个使用文件管道的异步解决方案。

代码语言:javascript
复制
import threading
import sys
import os

class Capturing():
    def __init__(self):
        self._stdout = None
        self._stderr = None
        self._r = None
        self._w = None
        self._thread = None
        self._on_readline_cb = None

    def _handler(self):
        while not self._w.closed:
            try:
                while True:
                    line = self._r.readline()
                    if len(line) == 0: break
                    if self._on_readline_cb: self._on_readline_cb(line)
            except:
                break

    def print(self, s, end=""):
        print(s, file=self._stdout, end=end)

    def on_readline(self, callback):
        self._on_readline_cb = callback

    def start(self):
        self._stdout = sys.stdout
        self._stderr = sys.stderr
        r, w = os.pipe()
        r, w = os.fdopen(r, 'r'), os.fdopen(w, 'w', 1)
        self._r = r
        self._w = w
        sys.stdout = self._w
        sys.stderr = self._w
        self._thread = threading.Thread(target=self._handler)
        self._thread.start()

    def stop(self):
        self._w.close()
        if self._thread: self._thread.join()
        self._r.close()
        sys.stdout = self._stdout
        sys.stderr = self._stderr

示例用法:

代码语言:javascript
复制
from Capturing import *
import time

capturing = Capturing()

def on_read(line):
    # do something with the line
    capturing.print("got line: "+line)

capturing.on_readline(on_read)
capturing.start()
print("hello 1")
time.sleep(1)
print("hello 2")
time.sleep(1)
print("hello 3")
capturing.stop()
票数 3
EN

Stack Overflow用户

发布于 2021-12-30 06:40:46

基于kindallForeverWintr的回答。

我为Python<3.4创建了redirect_stdout函数

代码语言:javascript
复制
import io
from contextlib import contextmanager

@contextmanager
def redirect_stdout(f):
    try:
        _stdout = sys.stdout
        sys.stdout = f
        yield
    finally:
        sys.stdout = _stdout


f = io.StringIO()
with redirect_stdout(f):
    do_something()
out = f.getvalue()
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16571150

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档