1

我有兴趣跟踪 for 循环的执行。具体来说,我想在 for 循环退出时在屏幕上打印一条消息。问题是我无法控制 for 循环,也就是说,其他人会将我的代码传递给 for 循环以进行跟踪。这是一些示例代码:

import sys
import linecache           

def trace_calls(frame, event, arg): 
    if event != 'call':    
        return             
    co = frame.f_code      
    func_name = co.co_name 
    if func_name == 'write':
        return             
    return trace_lines

def trace_lines(frame, event, arg): 
    if event != 'line':
        return
    co = frame.f_code
    line_no = frame.f_lineno
    filename = co.co_filename
    print("%d %s"%(line_no, linecache.getline(filename, line_no)[:-1]))

def some_elses_code():
    j = 0
    for i in xrange(0,5):
       j = j + i
    return j

if __name__ == "__main__":
    sys.settrace(trace_calls)
    some_elses_code()

以及代码的输出:

22     j = 0
23     for i in xrange(0,5):
24         j = j + i
23     for i in xrange(0,5):
24         j = j + i
23     for i in xrange(0,5):
24         j = j + i
23     for i in xrange(0,5):
24         j = j + i
23     for i in xrange(0,5):
24         j = j + i
23     for i in xrange(0,5):
25     return j

我知道我可以只看行号,看到已经执行的行不是下一行,但感觉不对。我想检查传递给 trace_lines 方法的框架对象,并查看 for 循环中使用的迭代器没有更多项目。 这个链接说for循环捕获了一个异常,然后它知道迭代器都用完了,但是我看不到框架对象上填充的任何异常对象(即frame.f_exc_value总是无)。此外,我在本地范围内没有看到 var 是 for 循环中使用的迭代器。这样的事情可能吗?

4

1 回答 1

2

循环创建的迭代器对for循环是私有的,并保存在 Python 堆栈中,每次执行时都会保留GET_ITER拾取-FOR_ITER这就是为什么您在本地人中看不到它的原因。

FOR_ITER确实通过捕获迭代器引发的循环来终止循环StopIteration,但这是通过直接检查是否tp_iternext返回NULL来测试的,因此异常在有机会传播到 Python 帧之前被捕获并清除。但是即使您可以访问迭代器,也几乎无法使用它,因为 Python 迭代器不支持窥视。

由于 Python 的跟踪机制在进入或离开块时不会调用跟踪回调for,因此您似乎需要借助诸如处理line事件之类的技巧来发现循环已退出。

于 2012-10-21T21:38:21.860 回答