入れ子関数は、親関数内に特定の機能をカプセル化する便利な手段を提供します。ただし、クロージャーの動作により、アクセスしやすさとローカル変数の値に関していくつかの複雑な問題が発生する可能性があります。
問題:
次のコード スニペットを考えてみましょう:
from functools import partial class Cage(object): def __init__(self, animal): self.animal = animal def gotimes(do_the_petting): do_the_petting() def get_petters(): for animal in ['cow', 'dog', 'cat']: cage = Cage(animal) def pet_function(): print("Mary pets the " + cage.animal + ".") yield (animal, partial(gotimes, pet_function)) funs = list(get_petters()) for name, f in funs: print(name + ":", f())
望ましい動作は、それぞれに 3 つの異なる動物 (「牛」、「犬」、「猫」) を出力することです。反復。ただし、プログラムはすべての反復で「cat」のみを出力します。この動作は、ローカル変数ケージが入れ子関数に関連付けられているという期待と矛盾します。
答え:
誤解は、入れ子関数が参照を格納するという仮定にあります。定義時に親スコープのローカル変数に追加されます。実際には、ネストされた関数は、実行時にのみ親スコープから変数を検索します。
この特定の例では、pet_function 用に作成されたクロージャーは、get_petters 関数からのケージ変数にインデックスを付けます。 pet_function が呼び出されると、クロージャにアクセスしてケージの値を取得します。ただし、その時点で get_petters 関数は完了しており、ケージ変数の最終値は「cat」になります。したがって、pet_function バリエーションへの後続の呼び出しはすべて、値 'cat' を返します。
回避策:
この問題を解決するには、さまざまな手法を使用して、ネストされた関数は、ケージの正しい値にアクセスします:
これらのアプローチのいずれかを採用することで、入れ子関数が反復ごとに意図したローカル変数に確実にアクセスできるようになります。
以上が入れ子関数が親関数のローカル変数の最終値にのみアクセスするのはなぜですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。