我有一个程序,它依赖于一个大型代码库,它会打印出许多不相关和烦人的消息。我想清理一下它们,但由于它们的内容是动态生成的,我不能只为它们 grep。
有没有办法在打印语句上放置一个钩子?(我使用 python 2.4,但我会对任何版本的结果感兴趣)。有没有另一种方法可以找到输出来自哪个“打印”语句?
我有一个程序,它依赖于一个大型代码库,它会打印出许多不相关和烦人的消息。我想清理一下它们,但由于它们的内容是动态生成的,我不能只为它们 grep。
有没有办法在打印语句上放置一个钩子?(我使用 python 2.4,但我会对任何版本的结果感兴趣)。有没有另一种方法可以找到输出来自哪个“打印”语句?
严格来说,您所依赖的代码库(如在库中)不应包含任何 print
语句。所以,你真的应该把它们全部删除。
除此之外,您可以进行猴子补丁stdout
:将日期时间戳添加到 Python 打印
对于 CPython2.5 或更早版本:
import sys
import inspect
import collections
_stdout = sys.stdout
Record = collections.namedtuple(
'Record',
'frame filename line_number function_name lines index')
class MyStream(object):
def __init__(self, target):
self.target = target
def write(self, text):
if text.strip():
record = Record(*inspect.getouterframes(inspect.currentframe())[1])
self.target.write(
'{f} {n}: '.format(f = record.filename, n = record.line_number))
self.target.write(text)
sys.stdout = MyStream(sys.stdout)
def foo():
print('Hi')
foo()
产量
/home/unutbu/pybin/test.py 20: Hi
对于 CPython2.6+,我们可以导入 print 函数
from __future__ import print_function
然后按照我们的意愿重定向它:
from __future__ import print_function
import sys
import inspect
import collections
Record = collections.namedtuple(
'Record',
'frame filename line_number function_name lines index')
def myprint(text):
if text.strip():
record = Record(*inspect.getouterframes(inspect.currentframe())[1])
sys.stdout.write('{f} {n}: '.format(f = record.filename, n = record.line_number))
sys.stdout.write(text + '\n')
def foo():
print('Hi')
print = myprint
foo()
请注意,inspect.currentframe
使用sys._getframe
which 不是 Python 的所有实现的一部分。所以上面的解决方案可能只适用于 CPython。
完成这项工作的一个非常严重的黑客攻击:
使用您最喜欢的文本编辑器,使用您的搜索/查找功能。
找到所有的打印语句。
并手动输入一个数字或标识符。(或者如果你这样做是自动的,那么脚本)
执行此操作的脚本很简单,只需print
使用正则表达式查找,然后将其替换为print ID,
,然后一切都会相同,但您会得到数字。
干杯。
编辑
除非有任何奇怪的格式,否则下面的代码应该为您完成。
请注意,这只是您可以做到的方式的一个示例。不是真正的答案。
import re
class inc():
def __init__(self):
self.x = 0
def get(self):
self.x += 1
return self.x
def replacer(filename_in, filename_out):
i = inc()
out = open(filename_out, 'w')
with open(filename_in) as f:
for line in f:
out.write("%s\n" % re.sub(r'print', 'print %d,' % i.get(), line))
我使用了一个基本的增量器类,以防你想要某种更复杂的 ID,而不仅仅是一个计数器。
在恶劣的情况下(在一些奇怪的二进制库中完成输出),您也可以使用strace -e write
(以及更多选项)。如果您不读取 strace 的输出,则 strace 程序会一直等到您读取,因此您可以向它发送一个信号并查看它在哪里死掉。
这是Jeeeyul 为 Java 提出的一个技巧:将输出流 (ie sys.out
) 替换为在写入换行符时会注意到的内容。
如果此标志为真,则在写入下一个字节时抛出异常。在同一个地方捕获异常,沿着堆栈跟踪,直到找到不属于您的“调试流编写器”的代码。
伪代码:
class DebugPrintln:
def __init__(self):
self.wasLF = False
def write(self, x):
if self.wasLF:
self.wasLF = False
frames = traceback.extract_stack()
... find calling code and output it ...
if x == '\n':
self.wasLF = true
super.write(x)