2

我正在尝试编写一个程序,该程序将跟踪 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>
4

1 回答 1

2

事实证明,发生这种情况是因为collections.namedtuple做了一些非常奇怪的事情(并且DecimalTuple是 a namedtuple,因此您import decimal随后调用此代码的调用)。碰巧的是,在第 300 行左右collections.py(至少在 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>.

于 2012-05-27T06:49:11.903 回答