4

我有一个程序,它依赖于一个大型代码库,它会打印出许多不相关和烦人的消息。我想清理一下它们,但由于它们的内容是动态生成的,我不能只为它们 grep。

有没有办法在打印语句上放置一个钩子?(我使用 python 2.4,但我会对任何版本的结果感兴趣)。有没有另一种方法可以找到输出来自哪个“打印”语句?

4

5 回答 5

3

严格来说,您所依赖的代码库(如在库中)不应包含任何 print语句。所以,你真的应该把它们全部删除。

除此之外,您可以进行猴子补丁stdout将日期时间戳添加到 Python 打印

于 2012-11-22T14:46:33.557 回答
3

对于 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._getframewhich 不是 Python 的所有实现的一部分。所以上面的解决方案可能只适用于 CPython。

于 2012-11-22T15:30:27.420 回答
2

完成这项工作的一个非常严重的黑客攻击:

使用您最喜欢的文本编辑器,使用您的搜索/查找功能。

找到所有的打印语句。

并手动输入一个数字或标识符。(或者如果你这样做是自动的,那么脚本)

执行此操作的脚本很简单,只需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,而不仅仅是一个计数器。

于 2012-11-22T14:44:54.053 回答
1

在恶劣的情况下(在一些奇怪的二进制库中完成输出),您也可以使用strace -e write(以及更多选项)。如果您不读取 strace 的输出,则 strace 程序会一直等到您读取,因此您可以向它发送一个信号并查看它在哪里死掉。

于 2012-11-22T16:33:00.510 回答
1

这是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)
于 2012-11-22T14:50:02.887 回答