6

オブジェクトが割り当てられている名前を判別するためのコードを書いています。これは、一般的なデバッグ作業のためであり、Pythonの内部にさらに慣れるためのものです。

可能であれば、そのクラスのすべてのインスタンスに名前が記録されるように、クラスデコレータとして構造化しています。コードはかなり長いので、尋ねられない限り投稿しません。一般的なテクニックは次のとおりですが

  1. クラスの__init__メソッドをコードで装飾して、私がやりたいことを実行します

  2. 設定caller = inspect.currentframe().f_backして開きinspect.getframeinfo(caller).filename、に送信しast.parseます。ここではエラーチェックを行いません。これは、(1)これはデバッグ/プロファイリング/ハッキングのためだけのものです(2)この正確なプロセスが「完了したばかり」であるか、コードが実行されていないためです。これに問題はありますか?

  3. 現在実行中のメソッドを実行さast.Assignmentせるインスタンスを見つけます__init__

  4. その場合len(assignment.targets) == 1、左側にアイテムが1つしかないので、から名前を取得できますtargets[0].id。のような単純な形式a = Foo()assignment.valueは、はのインスタンスですast.Call。リテラル(リストなど)の場合、value関心のあるオブジェクトが名前に割り当てられていないため、そのリストとベイルになります。

assignment.value.funcそれが実際type(obj).__call__に私が興味を持っているオブジェクトであることを確認するための最良の方法は何ですか。それが「どこかにある」か、コードが実行されないことさえ保証されていると確信しています。私はそれがトップレベルにある必要があります。当然のことは、それを歩き、内部呼び出しが含まれていないことを確認することです。そうすれば、私は自分の名前を持っていることが保証されます。(私の推論は正しいです、その仮定が正しいかどうかはわかりません)。これは理想的ではありません。なぜなら、私が興味を持っている場合、それがであるかどうかわからないのでFoo、これは私を投げ捨てることにつながる可能性があるからです。 a = Foo(Bar())a = Bar(Foo())

もちろん、確認するassignment.value.func.idことはできますが、誰かがやった可能性がFoobar = Fooあるので、これに過度に依存したくありません。

どんな助けでも大歓迎です。いつものように、私は見落としているかもしれない他の提案や問題に興味があります。

また、「python-internals」タグを発明しなければならなかったことに本当に驚いています。

4

4 に答える 4

2

ASTはあなたにその答えを与えることはできません。frame.f_lastiを使用してから、バイトコードを確認してみてください。次の行がSTORE_FASTでない場合は、探している単純な割り当て以外の内部呼び出しなどが発生しています。

def f():
  f = sys._getframe()
  i = f.f_lasti + 3   # capture current point of execution, advance to expected store
  print dis.disco(f.f_code, i)
于 2010-09-25T00:26:46.173 に答える
0

ここではエラーチェックを行いません。これは、(1)これはデバッグ/プロファイリング/ハッキングのためだけのものです(2)この正確なプロセスが「完了したばかり」であるか、コードが実行されていないためです。これに問題はありますか?

はい:

  1. プログラムを開始する

  2. 特定のモジュールfoo.pyをインポートするユニットを待機します

  3. foo.pyを編集する

Pythonプロセスに読み込まれるコードは、ディスクにあるコードと一致しなくなりました。

バイトコードを逆アセンブルするさらに別の理由は、より良い手法かもしれません。

于 2010-09-28T02:35:26.023 に答える
0

これがどれほど役立つかはわかりませんが、への呼び出しを使用することを検討しましたlocals()か?dictすべてのローカル変数の名前と値を含むを返します。

例えば:

s = ''
locals()
>>> {'__builtins__': <module '__builtin__' (built-in)>, '__package__': None, 's': '', '__name__': '__main__', '__doc__': None}
t = s  # I think this is what is of most importance to you
locals()
>>> {'__builtins__': <module '__builtin__' (built-in)>, '__package__': None, 's': '', 't': '', '__name__': '__main__', '__doc__': None}

したがって、このディクショナリをトラバースして、探しているタイプのオブジェクトが(値として)どの変数にあるかを確認できます。

私が言ったように、私はこの答えがどれほど役立つかわかりませんが、何かについて説明が必要な場合は、コメントを残してください。できる限り対応するように努めます。

于 2010-09-26T13:13:17.633 に答える
0

これがその方法です。匿名の手がかりを与える人に感謝します。あなたのaltアカウントの担当者を獲得するためのあなたの探求に多くの幸運があります。

import inspect
import opcode


def get_name(f):
    """Gets the name that the return value of a function is
    assigned to. 

    This could be modified for classes as well. This is a
    basic version for illustration that only prints out
    the assignment instead of trying to do anything with it.
    A more flexible way would be to pass it a callback for when
    it identified an assignment.

    It does nothing for assignment to attributes. The solution
    for that isn't much more complicated though. If the
    instruction after the function call is a a `LOAD_GLOBAL`,
    `LOAD_FAST` or `LOAD_DEREF`, then it should be followed by
    a chain of `LOAD_ATTR`'s. The last one is the attribute
    assigned to.
    """

    def inner(*args, **kwargs):
        name = None

        frame = inspect.currentframe().f_back
        i = frame.f_lasti + 3

        # get the name if it exists
        code = frame.f_code
        instr = ord(code.co_code[i])
        arg = ord(code.co_code[i+1]) # no extended arg here.
        if instr == opcode.opmap['STORE_FAST']:
            name = code.co_varnames[arg]
        elif instr in (opcode.opmap['STORE_GLOBAL'],
                       opcode.opmap['STORE_NAME']):
            name = code.co_names[arg]
        elif instr == opcode.opmap['STORE_DEREF']:
            try:
                name = code.co_cellvars[arg]
            except IndexError:
                name = code.co_freevars[arg - len(code.co_cellvars)]
        ret = f(*args, **kwargs)
        print opcode.opname[instr]
        if name:
            print "{0} = {1}".format(name, ret)
        return ret

    return inner


@get_name
def square(x):
    return x**2

def test_local():
    x = square(2)

def test_deref():
    x = square(2)
    def closure():
        y = x
    return closure

x = square(2)
test_local()
test_deref()()

を使用しlist_[i] = foo()ての値を含め、どちらのの割り当ても理解するのはそれほど難しいことではありません。トリッキーなものはリテラルになり、引数として渡されたときです。これらのケースはどちらもかなり難しいはずです。iframe.f_locals

于 2010-11-16T02:28:25.013 に答える