返された後にcount_calls_bad
のバージョンに追加された関数属性が保持されないのはなぜですか?(デコレータは渡されたfuncに.calls
を追加します)私は2番目の(良い)バージョンが内側の関数の内部にバインドされているのに対して、func属性がバインドされているクロージャを作成しようとする悪いバージョンを理解していますが、 "悪い"バージョンは、 「良い」バージョンと同じ結果を得ることができます。decorator to track number関数呼び出し - 動作していない
def count_calls_bad(func):
func.calls = 0
def inner(*args,**kwargs):
func.calls += 1 #each call to inner increments func.calls (recur_n.calls)
return func(*args,**kwargs)
return inner
def count_calls_good(func):
def inner(*args, **kwargs):
inner.calls += 1
return func(*args, **kwargs)
inner.calls = 0
return inner
@count_calls_bad
def recur_n(num):
if num == 0:
return 0
print (num)
return recur_n(num-1)
recur_n(10)
print(recur_n.calls) #recur_n.calls attribute not bound any longer
UPDATE:固定コードは、エディタでテストした後、関数名を更新するのを忘れていました。今recur_nが呼び出され、recur_10は呼び出されません。
また、私が遊んと問題がrecur_nがinner
になっていると思いますし、その最後の行print(recur_n.calls)
は本当にprint(function count_calls_bad.<locals>.inner at 0x000000000364E2F0>)
で、コールがrecur_n
実際装飾されていない上に結合されて以来、そのオブジェクトは、何の属性calls
を持っていませんでした。
あなたが実際にオリジナルの装飾のない関数にあなたの方法を強制すると、次の牛車で正しく更新された属性を取得することができます:
print(recur_n.__closure__[0].cell_contents.calls)
私の次の思考は、元の装飾のないを維持するためにfunctoolsの@wrapsを使用した後でしたこれは基本的に私が上でやっていることであり、デコレータに入り、装飾されていない名前のcall
属性を引き出します。
from functools import wraps
def count_calls_bad(func):
func.calls = 0
@wraps func
def inner(*args,**kwargs):
func.calls += 1 #each call to inner increments func.calls (recur_n.calls)
return func(*args,**kwargs)
return inner
これは少なくとも私に結果が得られますが、その結果はゼロです。だから、私は自分のオリジナルの質問に答えましたが、私は新しいもので終わります。なぜなら、@wrapsが関数を更新してrecur_nが内部ではなくrecur_nを参照するようになったから、11ではなく0が得られるのですか?
@wrapsは関数のシグネチャをコピーしますが、変数や属性などの他のデータを参照またはコピーすることはできません。