我想处理第三部分脚本的实时输出,打印一些与图案相匹配但跳过其他的行:
def thirdparty_code():
from random import choice
stuff = ['keep: important stuff', 'ignore: boring stuff']
while True:
chosen_line = choice(stuff)
print(chosen_line)
我使用redirect_stdout
(将行传递到我的虚拟IO(和一个扩展的StringIO
(用作IO,但也称为我的过滤功能(。但是,当我在处理功能的内部调用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()
我想知道是否有可能逃离重定向,例如在print()
功能中指定file
参数,以便将其打印到实际的标准输出。我知道我可以轻松地使用标准错误流:
import sys
print(line, file=sys.stderr)
,但我特别想使用标准输出。是否有一种很好的Pythonic方法可以做到?
重定向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
一旦我写了我的问题,我才意识到,在调用重定向之前,只需将标准输出对象sys.stdout
保存到变量:
stdout = sys.stdout
def filter_boring_stuff_out(line):
if line.startswith('ignore'):
return
print(line, file=stdout)
,但是一如既往 - 我很乐意了解其他可能的解决方案。
您可以重定向stdout
并忽略以ignore
开头的所有消息。如果这样做,所有print
S将被拦截。如果您试图从无法访问或不想更改的代码中过滤消息,这将更好。
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