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は常にNoneです)。さらに、forループで使用されるイテレータであるvarがローカルスコープに表示されません。このようなことは可能ですか?

4

1 に答える 1

2

ループによって作成されたイテレータはforループ専用であり、Pythonスタックに保持され、実行されるたびにそこに残さGET_ITER取得さFOR_ITERれます。これが、ローカルでは見られない理由です。

FOR_ITERStopIterationイテレータによって発生したキャッチによってループを終了しますが、これは返されたかどうかを直接チェックすることtp_iternextNULLによってテストされるため、Pythonフレームに伝播する機会を得る前に、例外がキャッチされてクリアされます。ただし、イテレータにアクセスできたとしても、Pythonイテレータはピークをサポートしていないため、イテレータでできることはほとんどありません。

Pythonのトレースメカニズムは、ブロックが開始または終了したときにトレースコールバックを呼び出さないため、ループが終了したことを確認するために、イベントのfor処理などのハックに頼る必要があるようです。line

于 2012-10-21T21:38:21.860 に答える