如何从Python中的标准输出重定向转义

时间:2019-05-22 15:30:44

标签: python python-3.x contextmanager stringio

我想处理第三方脚本的实时输出,打印一些匹配模式的行,但跳过其他行:

coordinates

我使用def thirdparty_code(): from random import choice stuff = ['keep: important stuff', 'ignore: boring stuff'] while True: chosen_line = choice(stuff) print(chosen_line) (将线传递到虚拟IO)和扩展的redirect_stdout(用作IO,但也调用过滤功能)。但是,当我在处理函数中调用StringIO时,会得到print()-这并不意外:

RecursionError

我想知道是否有可能摆脱重定向,例如在from io import StringIO from contextlib import redirect_stdout class StringIOWithCallback(StringIO): def __init__(self, callback, **kwargs): super().__init__(**kwargs) self.callback = callback def write(self, s): super().write(s) self.callback(s) def filter_boring_stuff_out(line): if line.startswith('ignore'): return print(line) my_io = StringIOWithCallback(filter_boring_stuff_out) with redirect_stdout(my_io): thirdparty_code() 函数中指定file参数,以便将其打印到实际的标准输出。我知道我可以轻松使用标准错误流:

print()

但是我特别想使用标准输出。有一种不错的,Python方式的方法吗?

3 个答案:

答案 0 :(得分:3)

重定向stdout后,您可以通过__stdout__轻松地将其重置,因为它可以保存原始值。

sys.stdout = redirected_stdout
...
...
sys.stdout = sys.__stdout__

如果您不断发现自己在切换这些输出流,则应该创建一个函数以输出到重定向的流:

def redirect(*args):
    print(*args, file=redirected_file)

redirect(...)  # redirect this output
print(...)  # use standard stream

答案 1 :(得分:1)

一旦我写了我的问题,我已经意识到在调用重定向之前,只需要将标准输出对象import sys print(line, file=sys.stderr) 保存到一个变量中即可。

sys.stdout

但一如既往-我很乐意了解其他可能的解决方案。

答案 2 :(得分:1)

您可以重定向stdout并忽略所有以ignore开头的消息。如果您这样做,所有print都将被拦截。如果您尝试从您无权访问或不想更改的代码中过滤消息,则此方法会更好。

import sys
from contextlib import redirect_stdout

class Filter_Out:
    def __init__(self, *_, start=None, anywhere=None, end=None):
        self.last_ignore = False
        self.start = start
        self.anywhere = anywhere
        self.end = end
        self.terminal = sys.stdout
    def write(self, txt):
        if (self.start and txt.startswith(self.start)) or \
           (self.end and txt.endswith(self.end)) or \
           (self.anywhere and self.anywhere in txt):
            self.last_ignore = True
            return
        if self.last_ignore and txt == '\n':
            self.last_ignore = False
        else:
            self.terminal.write(txt)
    def flush(self):
        pass

with redirect_stdout(Filter_Out(start='ignore', anywhere='4')):
    print("test")
    print("test2")
    print("ignore: test2") # will not print because it started with ignore
    print("test1")
    print("test42") # will not print because it had 4 in it