2

以下を参照する関数デバッグ デコレータを作成しようとしています。

def foo(baz):
  bar = 1
  bar = 2
  return bar

そしてそれを次のようにラップします:

def foo(baz):
  bar = 1
  print 'bar: {}'.format(bar)
  bar = 2
  print 'bar: {}'.format(bar)
  return bar

「\w+(?=\s*[=])」を取得するために、関数をテキストとして操作する必要がありますが、それにアクセスする方法がわかりません。動作するブログから変更したデコレータがありますが、次のように変更してみました:

class decorator_string_check(object):

   def __init__(self, func):
        self.func = func
        wraps(func)(self)

   def __call__(self, *args, **kwargs):
        print dir(self.func)
        print dir(self.func.__code__)
        print self.func.__code__.__str__()
        ret = self.func(*args, **kwargs)
        return ret

@decorator_string_check
def fake(x):
    y = 6
    y = x
    return y

y = fake(9)

つまり、価値のあるものは何も得ていません。

['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']
['__class__', '__cmp__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'co_argcount', 'co_cellvars', 'co_code', 'co_consts', 'co_filename', 'co_firstlineno', 'co_flags', 'co_freevars', 'co_lnotab', 'co_name', 'co_names', 'co_nlocals', 'co_stacksize', 'co_varnames']
<code object fake at 0x7f98b8b1d030, file "./logging.py", line 48>

実際の "func" テキストを操作して正規表現を実行し、デコレータ クラス オブジェクト内で必要なものを見つけるにはどうすればよいですか? ありがとうございました

4

1 に答える 1

6

まず、そのようなことはしないことをお勧めします。動作するコードを取得するのは難しく、正しいバージョンを作成するのは非常に困難です。

その上、あなたが何をしたいのか正確にはわかりません。このデコレーターは、printすべての割り当ての後にステートメントを追加し、更新された値を表示する必要がありますか? または、変数の特定のサブセットのみを追跡しますか?

つまり、何かのソースコードを取得するには、inspectモジュール、特にgetsource関数を使用できます。

In [1]: def test():
   ...:     a = 1
   ...:     b = 2
   ...:     

In [2]: import inspect

In [3]: inspect.getsource(test)
Out[3]: 'def test():\n    a = 1\n    b = 2\n'
In [4]: print(inspect.getsource(test))
def test():
    a = 1
    b = 2

必要に応じてソース コードを変更して検査し、最後compile()に新しいソース コードを確認することができます。

ただし、次のことに注意してください。

  • 構文的に無効なコード (複数行の式など) を作成しやすいため、ソース コードを変更するときは注意が必要です。
  • コンパイルするときは、元の関数と同じスコープでコンパイルしたいと思います。このinspectモジュールには、デコレーターが呼び出されるスタックフレームを取得できる関数がいくつかあり、そこから環境を取得できます。スタックの処理方法については、こちらをお読みください。
  • ソースコードが利用できない場合があります。コードがバイトコードにコンパイルされ、元のファイルが削除される可能性があります。この場合getsource、単純にOSError.

より「健全な」解決策は、ソース コードではなく bytecode を見ることですdisモジュールを使用してこれを行うことができます。変数の値がいつ変更されるかを確認し、その変数を出力するバイトコードを挿入することができます。

このdisモジュールは python3.4+ で大幅に拡張されたため、以前のバージョンの python ではおそらく難しいことに注意してください。

これを試す前に、おそらくPython バイトコード ハック、gotos revisitedなどの記事を読む必要があります。バイトコードを見て、それを操作する方法についてのアイデアを提供します。

これはおそらくより安全です (たとえば、ソース ファイルがマシン上に存在しなくてもバイトコードにアクセスできます) が、演習として以外は、あなたが念頭に置いていることは良いことではないと思います。


jsbueno が指摘しているように、必要なこと (つまり、python デバッガー) を実行する適切な方法は、sys.settrace.

この関数を使用すると、実行される「コード」ごとに呼び出されるトレース関数を設定できます。関数は、関数が呼び出されたとき、新しいブロックが入力されたときなどを認識します。コードが実行されるフレームにアクセスできるため、関心のある値を見つけることができるはずです。

ファイルをチェックして、lnotab_notes.txtこの関数の引数として提供されたデータをソース コードの位置にマップして、割り当てがいつ実行されるかを理解する必要があります。

時間があるとき (おそらく来週の終わり) に、このアプローチに基づいて何かを実装して、それを実証しようとします。

于 2015-06-19T18:01:50.157 に答える