使用sys.settrace()时,代码对象在导入期间具有意外的文件名

时间:2012-05-27 05:28:01

标签: python debugging tracing

我正在尝试编写一个程序,该程序将跟踪Python代码并打印局部变量值更改的报告。我已经通过简单的赋值,循环和函数调用很好地工作了,但是当我使用import语句时我遇到了问题。

我只想跟踪主模块中的代码,我想在调用导入的模块后立即停止跟踪。当我导入一个我编写的简单模块时,我可以这样做,当帧的代码对象指向另一个文件时,我就停止跟踪。

但是,当我尝试导入decimal模块时,这不起作用。我可以删除decimal模块中运行的大多数代码,但是我只调用一个名为DecimalTuple的代码块,该代码块声称在主模块中运行。但这没有任何意义,因为该模块中不存在行号。

我可以使用框架或代码对象上的其他一些属性来告诉DecimalTuple不在主模块中吗?显然,我可以为DecimalTuple添加一个特例,但如果其他模块遇到同样的问题,这对我没有帮助。

这是我的例子。它执行引用的代码并使用settrace()跟踪调用。如果你注释掉global_trace()的前两行,它也会显示在其他模块中执行的所有代码。

import sys

class tracer:

    count = 0

    def __init__(self):
        self.index = tracer.count = tracer.count + 1

    def global_trace(self, frame, event, arg):
        if frame.f_code.co_filename != '<string>':
            return
        print 'global %d, line %d: %s, %s' % (self.index,
                                         frame.f_lineno,
                                         event,
                                         frame.f_code)
        return tracer().local_trace

    def local_trace(self, frame, event, arg):
        print 'local %d, line %d: %s, %s' % (self.index,
                                         frame.f_lineno,
                                         event,
                                         frame.f_code)
        return self.local_trace

code = """\
def foo(r):
    return r + 3

y = foo(2)

import decimal

x = decimal.Decimal('10')
"""

sys.settrace(tracer().global_trace)

exec code in dict()

这是跟踪输出。您可以看到对foo()的调用及其执行都在<string>模块中,该模块表示我作为主模块传递的代码字符串。但是,当它到达第6行的import语句时,它开始调用不可能在<string>模块中的代码。

global 1, line 1: call, <code object <module> at 0x266a030, file "<string>", line 1>
local 2, line 1: line, <code object <module> at 0x266a030, file "<string>", line 1>
local 2, line 4: line, <code object <module> at 0x266a030, file "<string>", line 1>
global 1, line 1: call, <code object foo at 0x266a730, file "<string>", line 1>
local 3, line 2: line, <code object foo at 0x266a730, file "<string>", line 1>
local 3, line 2: return, <code object foo at 0x266a730, file "<string>", line 1>
local 2, line 6: line, <code object <module> at 0x266a030, file "<string>", line 1>
global 1, line 1: call, <code object <module> at 0x27c2130, file "<string>", line 1>
local 4, line 1: line, <code object <module> at 0x27c2130, file "<string>", line 1>
global 1, line 1: call, <code object DecimalTuple at 0x27c21b0, file "<string>", line 1>
local 5, line 1: line, <code object DecimalTuple at 0x27c21b0, file "<string>", line 1>
local 5, line 2: line, <code object DecimalTuple at 0x27c21b0, file "<string>", line 1>
local 5, line 4: line, <code object DecimalTuple at 0x27c21b0, file "<string>", line 1>
local 5, line 6: line, <code object DecimalTuple at 0x27c21b0, file "<string>", line 1>
local 5, line 8: line, <code object DecimalTuple at 0x27c21b0, file "<string>", line 1>
local 5, line 12: line, <code object DecimalTuple at 0x27c21b0, file "<string>", line 1>
local 5, line 13: line, <code object DecimalTuple at 0x27c21b0, file "<string>", line 1>
local 5, line 20: line, <code object DecimalTuple at 0x27c21b0, file "<string>", line 1>
local 5, line 24: line, <code object DecimalTuple at 0x27c21b0, file "<string>", line 1>
local 5, line 28: line, <code object DecimalTuple at 0x27c21b0, file "<string>", line 1>
local 5, line 30: line, <code object DecimalTuple at 0x27c21b0, file "<string>", line 1>
local 5, line 37: line, <code object DecimalTuple at 0x27c21b0, file "<string>", line 1>
local 5, line 41: line, <code object DecimalTuple at 0x27c21b0, file "<string>", line 1>
local 5, line 42: line, <code object DecimalTuple at 0x27c21b0, file "<string>", line 1>
local 5, line 43: line, <code object DecimalTuple at 0x27c21b0, file "<string>", line 1>
local 5, line 43: return, <code object DecimalTuple at 0x27c21b0, file "<string>", line 1>
local 4, line 1: return, <code object <module> at 0x27c2130, file "<string>", line 1>
local 2, line 8: line, <code object <module> at 0x266a030, file "<string>", line 1>
local 2, line 8: return, <code object <module> at 0x266a030, file "<string>", line 1>

1 个答案:

答案 0 :(得分:2)

事实证明,这种情况发生了,因为collections.namedtuple执行了一些非常隐蔽的事情(DecimalTuplenamedtuple,因此您对import decimal的调用随后会调用此代码)。实际上,在collections.py的第300行(至少在Python 2.7中 - 您的行号可能在不同版本中有所不同)中,您会看到一条评论:

# Execute the template string in a temporary namespace and
# support tracing utilities by setting a value for frame.f_globals['__name__']

此后的代码会导致您的跟踪器误解它正在观察的内容 - 因为创建类的模板是使用exec本身完成的,在<string>“文件中执行的代码更多,只是不你的 <string>