我想通过我的Python程序过滤屏幕打印。
理想情况下,指定一个“打印黑名单”会很好,例如这个。
*FutureWarning*
INFO*
当部分屏幕打印输出与上述模式之一匹配时,整个打印输出将被过滤掉。
我很惊讶没有人提出这个问题,因为我认为这非常有用,因为没有它,我需要经历不同类型的屏幕打印并相应地处理它们。你可以想象其中一些可能是由于print
,有些是warning
等等。
我正在使用bash运行我的Python脚本,所以也欢迎基于bash的方法!
答案 0 :(得分:1)
您可以将print
变量绑定到您的自定义函数,以检查您不想看到的任何输出。
以下是一个例子:
>>> def print(*args, **kwargs):
... import builtins
... if not any(str(s).startswith('INFO') for s in args):
... builtins.print(*args, **kwargs)
答案 1 :(得分:1)
你说你愿意做bash。您可以编写另一个脚本,例如filter.py
:
from sys import stdin
def print_filtered(line):
if line.startswith("print this"):
print(line, end='') # The line includes its own newline character
for line in stdin:
print_filtered(line)
当然,您可以在print_filtered()
中添加所需的任何过滤选项。你甚至可以做一些替换;也许你想在打印之前删除字符串的print this
部分。
现在任何你想要过滤输出的程序,都可以这样运行:
$ python myfile.py | python filter.py
Rishav在评论中也提到可以用自定义对象替换sys.stdout
。我不是很喜欢这个想法,但你可以用这样的东西做到这一点:
import sys
class FilteredPrinter(object):
def __init__(self, filtered_print, stdout):
self._filtered_print = filtered_print
self._stdout = stdout
def _write(self, string):
self._filtered_print(string, self._stdout)
def __getattr__(self, attr):
if attr == 'write':
return self._write
return getattr(self._stdout, attr)
def filtered_print(string, stdout):
if string == "\n" or string.startswith("print this"):
stdout.write(string)
sys.stdout = FilteredPrinter(filtered_print, sys.stdout)
print("print this: my text")
print("print this text")
print("Don't print this")
使用此解决方案,您可以指定所需的任何过滤器;您也可以使用sys.stderr
执行此操作。如果您想返回旧版,请使用sys.stdout = sys.stdout._stdout
。请注意,print
函数为每个参数调用sys.stdout.write()
一次,并再次为换行符调用print("first", "second")
函数。也就是说,调用sys.stdout.write("first")
sys.stdout.write(" ")
sys.stdout.write("second")
sys.stdout.write("\n")
将执行此操作:
{{1}}
因此,在编写过滤函数时,请务必牢记这一点。
答案 2 :(得分:1)
我想通过我的Python程序过滤屏幕打印。
您可以使用Python的logging
模块,通过它输出所有打印和警告输出:
# in your main module
import logging
# -- log all output to myapp.log
logging.basicConfig(filename='myapp.log', level=logging.DEBUG)
# -- OR log all output to console
logging.basicConfig(level=logging.DEBUG)
# route all output to logging
logging.captureWarnings(True)
print = logging.info
添加您自己的Filter
以根据所需关键字过滤所有输出:
# define Filter in its own module, say logfilter.py
class OutputFilter(logging.Filter):
def __init__(self, keywords, name=None):
super(OutputFilter, self).__init__(name)
self.keywords = keywords
def filter(self, record):
msg = record.getMessage()
return not any(k in msg for k in self.keywords)
# add this in your main module
from logfilter import OutputFilter
flt = OutputFilter(['*FutureWarning*', 'INFO*'])
logger = logging.getLogger() # root logger
logger.addFilter(flt)
warnLogger = logging.getLogger('py.warnings') # warnings logger
warnLogger.addFilter(flt)
(...)没有它,我需要经历不同类型的屏幕打印输出并相应地处理它们。
如果您可以更改源代码,最好始终使用模块记录器而不是print:
# in any module with output, right after imports
logger = logging.getLogger(__name__)
...
# instead of print
logger.info(...)
logger.error(...)
logger.debug(...)
优点是logging
允许您对输出内容和位置进行非常精细的控制,同时从中心位置配置所有内容。
例如,虽然上面使用适用于所有日志记录输出的根记录器,但应用程序的每个模块都可以拥有自己的记录器,具有特定的配置,例如
# somewhere in your main module
# -- basic config is to console
logging.basicConfig(level=logging.DEBUG)
# -- module A output should go into its own file
logger = logging.getLogger('path.to.module.A')
handler = logging.FileHandler(filename='myapp-A.log') # see above
logger.setHandler(handler)
logger.setLevel(logging.INFO)
# path/to/module/A.py
# -- right at the top of the module
import logging
logger = logging.getLogger(__name__)
...
# in the actual code
logger.info('info message')
此示例将模块A的所有INFO消息路由到文件myapp-A.log
,而所有其他输出都发送到终端。
注意:从Python Logging Cookbook采用的所有示例。另请查看tutorial以获得更深入的解释。