この記事では、Pythonに関する関連知識を提供し、主にラムダのスコープに関する関連問題と、Python のクロージャーに関する関連コンテンツをまとめています。
【関連する推奨事項:Python3 ビデオ チュートリアル】
ラムダの書き方
def fun(): for i in range(3): yield lambda x : x * i f0, f1, f2 = fun() print(f0(1), f1(2), f2(3))
クロージャの書き方
def fun(): result = [] for i in range(3): def demo(x): return x * i result.append(demo) return result f0, f1, f2 = fun() print(f0(1), f1(2), f2(3))
上記 2 つの書き方の結果は 2, 4, 6 です。本来の考え方によれば、結果は 0, 2, 6 になるはずです。
問題の原因:
問題の根本は、Python の変数検索ルール LEGB (local、included、global、bultin) にあります。上記の例では、 , i は Closure スコープ (囲み) にあり、Python のクロージャは遅延バインディングであり、クロージャで使用されている変数 i の値は、内部関数が呼び出されたときに見つかります。
解決策
クロージャのスコープをローカルスコープに変更する
ラムダの書き方
def fun(): for i in range(3): yield lambda x, i = i: x * i f0, f1, f2 = fun() print(f0(1), f1(2), f2(3))
クロージャの書き方
def fun(): result = [] for i in range(3): def demo(x, i=i): return x * i result.append(demo) return result f0, f1, f2 = fun() print(f0(1), f1(2), f2(3))
上記の出力結果は 0, 2, 6
#別の状況:
def fun(): for i in range(3): yield lambda x : x * i f0, f1, f2 = fun() print(f0(1), f1(2), f2(3))
問題の原因
fun() メソッドによって返されるジェネレーター (またはイテレーター) は実際には実行されませんが、呼び出されるたびに実行されます。 トラバーサル後に印刷が実行される場合、i 変数は最後の呼び出しの値を使用します。ラムダがクロージャ メソッドとみなされる場合、変数 i の値は依然としてクロージャ スコープ内にあります (ローカルではありません) Python の落とし穴 (クロージャとラムダ) 栗を見てみましょう最初def create(): return [lambda x:i*x for i in range(5)] for i in create(): print(i(2))
8 8 8 8 8create 関数の戻り値はリストであり、リストの各要素は関数、つまり入力パラメーター x に複数の i を乗算する関数です。予想された結果は 0、2、4、6、8 でしたが、結果は 5 と 8 で、予想外でした。 このトラップが発生する際に lambda がよく使われるため、lambda の問題だと思われるかもしれませんが、lambda は責任を負いたくないという意思表示をしています。問題の本質は、Python の属性検索ルール LEGB (ローカル、エンクロージング、グローバル、ブリティン) にあります。上記の例では、i はクロージャ スコープ (エンクロージング) 内にあり、Python のクロージャは遅延バインディングです。これは、次のことを意味します。内部関数が呼び出されるときに、クロージャで使用される変数の値が照会されます。 解決策も非常に簡単で、クロージャのスコープをローカル スコープに変更するだけです。
def create(): return [lambda x, i=i:i*x for i in range(5)] for i in create(): print(i(2))
def create(): a = [] for i in range(5): def demo(x, i=i): return x*i a.append(demo) return a for i in create(): print(i(2))
上記 2 つの書き方は同じです
結果:02
4
6
8
同様の問題を抱えた別の栗毛##コードは非常に単純です: (ステートメント: python3 質問)
nums = range(2,20) for i in nums: nums = filter(lambda x: x==i or x%i, nums) print(list(nums))
結果:
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 , 17, 18, 19]同様に、通常のロジックによれば、結果は次のようになります:[2, 3, 5, 7 、11、13、17、19 ]
問題の原因:
Python3 では、filter() 関数はイテレータを返します。したがって、実際には Executed は行われませんが、呼び出されるたびに実行されます (Python2 の filter() によって返される値リストにはこの現象はありません)
nums = range(2,20) for i in nums: nums = filter(lambda x,i=i: x==i or x%i, nums) print(list(nums))
結果:
[2, 3, 5, 7, 11, 13, 17, 19]【関連する推奨事項:Python3 ビデオ チュートリアル
以上がPython でのクロージャとラムダのスコープ分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。