1

何かの戦略が発生したときに、引数を受け取る単純なデコレータを作成しました(クラスの代わりに関数を使用)。行を追加すると、前の行の実行が中断されます。

コードは次のとおりです。

def my_decorator(sublabel):
    def duration_wrapper(f):

        print sublabel
        # Uncommenting this code will break the previous line - why?
        # if sublabel is None:
        #     sublabel = f.func_name

        def wrapped_function(*args, **kwargs):
            return f(*args, **kwargs)

        return wrapped_function

    return duration_wrapper

@my_decorator('me')
def myf(): pass

myf()

これらのコード行のコメントを解除すると、次の例外が発生します。

Traceback (most recent call last):
  File "test.py", line 16, in <module>
    @my_decorator('me')
  File "test.py", line 4, in duration_wrapper
    print sublabel
UnboundLocalError: local variable 'sublabel' referenced before assignment

これらの2行のコードのコメントを外すと壊れてしまう理由を誰かが説明できますか?

4

2 に答える 2

7

デコレータはクロージャであり、囲まれたスコープから参照される囲まれたスコープのすべてのラベルは、囲まれたスコープ内で静的なままである必要があります。囲んでいるスコープの変数を囲んでいるスコープから変更できるようにする場合は、次のように、変数を変更可能なオブジェクトでラップする必要があります。

def my_decorator(sublabel):
    sublabel = [sublabel]
    def duration_wrapper(f):

        print sublabel[0]
        if sublabel[0] is None:
            sublabel[0] = f.func_name

        def wrapped_function(*args, **kwargs):
            return f(*args, **kwargs)

        return wrapped_function

    return duration_wrapper

@Bakuriuがコメントで指摘しているように、Python 3はnonlocalこの制限を取り除くために導入されsublabelており、問題を回避するためにグローバルを作成することもできますが、グローバルは通常一般的に悪い考えです。

于 2012-12-06T15:54:43.270 に答える
2

あなたの問題はこの簡単な例に減らすことができます

sublevel = 1

def func():
    print sublevel
    sublevel = 2

func()

問題は、外部スコープ(グローバルレベルまたは親関数レベルのスコープ)をマスクしている内部スコープに変数を割り当てる場合、ドキュメントを読んでPythonスコープルールがどのように機能するかを確認することです。注意すべき重要な点は次のとおりです。scopes are determined statically

global sublevelしたがって、私の例では、 printを呼び出す前に言う必要があり、ケースではnonlocalキーワード(python 3+)を使用する必要があります。

于 2012-12-06T16:03:16.397 に答える