如何找到打印声明的位置?

时间:2012-11-22 14:41:57

标签: python debugging io refactoring

我有一个程序,取决于一个大的代码库,打印了许多不相关和恼人的消息。我想稍微清理它们,但由于它们的内容是动态生成的,我不能只为它们加油。

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

5 个答案:

答案 0 :(得分:3)

严格地说,您所依赖的代码库(如库中)不应包含任何 print语句。所以,你应该真的只删除所有

除此之外,你可以猴子补丁stdoutAdding a datetime stamp to Python print

答案 1 :(得分: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 +,我们可以使用

导入打印功能
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,它不是所有Python实现的一部分。所以上面的解决方案可能仅适用于CPython。

答案 2 :(得分: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,而不是只有一个计数器。

答案 3 :(得分:1)

以下是Jeeeyul came up with for Java的一个技巧:将输出流(即sys.out)替换为写入换行符时注意到的内容。

如果此标志为true,则在写入下一个字节时抛出异常。在同一个地方捕获异常,沿堆栈跟踪向上走,直到找到不属于“调试流编写器”的代码。

伪代码:

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)

答案 4 :(得分:1)

在恶劣的环境中(在一些奇怪的二进制库中完成输出)你也可以使用strace -e write(以及更多选项)。如果你没有读取strace的输出,那么straced程序会等到你执行,所以你可以发送一个信号,看看它死了。