3

全て、

質問 2617120 に似た質問があります。ここにあります。

  • traceit を使用して関数入力変数を報告する方法

    質問者は、トレース フックを介して実行されたときに Python の出力関数パラメーターを作成する方法についてのポインターを求めていました。

    これに非常によく似たものを探していますが、ひねりがあります。すべてのデータがダンプされる代わりに、実行時にコードを評価し、評価された変数を出力したいと考えています。たとえば、次のコードを使用します。

    for modname in modnames:                   
    
    if not modname or '.' in modname:      
         continue                                                                    
    ...                                  
    

    トレース フックにより、次のように出力されます。

    for modname in modnames:                | for init in init,., encoding
                                            |
    if not modname or '.' in modname:       | if not init or '.' in init
         continue                           |     continue
    if not modname or '.' in modname:       | if not . or '.' in .
    ...                                     |
    

    コード行は、実行中のフレームに基づいて補間されます。特定の状況で命の恩人になる perl でこれを行いました。

    Pythonでこれを行うための最良の方法についてアイデアを持っている人はいますか? 私には自分の考えがありますが、人々の意見を聞きたいです (そして、既に作成済みの解決策がある場合)

    ここで、btw は参照コードです。

    import sys
    import linecache
    import random
    
    def traceit(frame, event, arg):
        if event == "line":
            lineno = frame.f_lineno
            filename = frame.f_globals["__file__"]
            if filename == "<stdin>":
                filename = "traceit.py"
            if (filename.endswith(".pyc") or
                filename.endswith(".pyo")):
                filename = filename[:-1]
            name = frame.f_globals["__name__"]
            line = linecache.getline(filename, lineno)
            print "%s:%s:%s: %s" % (name,  lineno,frame.f_code.co_name,line.rstrip())
        return traceit
    
    
    def main():
        print "In main"
        for i in range(5):
            print i, random.randrange(0, 10)
        print "Done."
    
    sys.settrace(traceit)
    main()
    
  • 4

    1 に答える 1

    0

    lineこれは、テキスト行と現在のスタック フレームが与えられたframe場合 (ちなみに、これは の内部関数であることを意図しています) 、手始めに何かを与える簡単なハックですtraceit

    import re
    from types import *
    
    def interpolatevar(matchobj):
        excludetypes = set((NoneType, TypeType, FunctionType, LambdaType, ClassType,
                        CodeType, InstanceType, MethodType, BuiltinFunctionType,
                        BuiltinMethodType))
    
        var = matchobj.group(0)
        basevar = var.split(".")[0]
        if basevar in frame.f_code.co_names or basevar in frame.f_code.co_varnames:
            if basevar in frame.f_globals or basevar in frame.f_locals:
                val = eval(var, frame.f_globals, frame.f_locals)
                if type(val) not in excludetypes:
                    return repr(val)
        return var
    
    line = re.sub(r"[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*", 
                  interpolatevar, line)
    

    これは正規表現を使用して識別子を見つけるため、文字列リテラルにある場合でもそれらを愚かに見つけますが、識別子は実際に関数で使用され、ローカルスコープまたはグローバルスコープで定義されている必要があります。

    それはオブジェクト属性アクセスを処理します (たとえば、私が最初に投稿したバージョンでは処理しませんでした)。foo.barさまざまなタイプの値を除外します。(もちろん、これらのタイプの値に興味がある場合、またはモジュールから他の値を追加できる場合、除外リストは簡単にカスタマイズできます。)foo<function foo at 0x02793470>types

    長期的には、どのトークンが実際に識別子であるかを特定する方が簡単なので、行のバイトコードを見ると有益かもしれないと思います。このastモジュールは、ステートメントの解析ツリーを生成するのにも役立つ可能性があります。これにより、識別子が何であるかを把握できますが、これは、一度に 1 行しか表示されない場合の条件とループでは問題になります。

    于 2010-12-08T15:00:04.530 に答える