もっと詳しく説明しようと思います。
もしあなたがそうするなら
i = 0
f = lambda: i
i囲んでいるスコープの変数にアクセスする関数(ラムダは本質的に関数です)を作成します。
内部的には、i. 大まかに言えば、異なる時点で異なる値を保持できる実数変数へのポインターのようなものです。
def a():
    # first, yield a function to access i
    yield lambda: i
    # now, set i to different values successively
    for i in range(100): yield
g = a() # create generator
f = next(g) # get the function
f() # -> error as i is not set yet
next(g)
f() # -> 0
next(g)
f() # -> 1
# and so on
f.func_closure # -> an object stemming from the local scope of a()
f.func_closure[0].cell_contents # -> the current value of this variable
ここで、 のすべての値はi、その時点で、そのクロージャーに格納されます。関数f()がそれらを必要とする場合。そこからそれらを取得します。
逆アセンブリ リストでその違いを確認できます。
これらは機能a()を述べ、f()次のように逆アセンブルします。
>>> dis.dis(a)
  2           0 LOAD_CLOSURE             0 (i)
              3 BUILD_TUPLE              1
              6 LOAD_CONST               1 (<code object <lambda> at 0xb72ea650, file "<stdin>", line 2>)
              9 MAKE_CLOSURE             0
             12 YIELD_VALUE
             13 POP_TOP
  3          14 SETUP_LOOP              25 (to 42)
             17 LOAD_GLOBAL              0 (range)
             20 LOAD_CONST               2 (100)
             23 CALL_FUNCTION            1
             26 GET_ITER
        >>   27 FOR_ITER                11 (to 41)
             30 STORE_DEREF              0 (i)
             33 LOAD_CONST               0 (None)
             36 YIELD_VALUE
             37 POP_TOP
             38 JUMP_ABSOLUTE           27
        >>   41 POP_BLOCK
        >>   42 LOAD_CONST               0 (None)
             45 RETURN_VALUE
>>> dis.dis(f)
  2           0 LOAD_DEREF               0 (i)
              3 RETURN_VALUE
b()それを次のような関数と比較してください
>>> def b():
...   for i in range(100): yield
>>> dis.dis(b)
  2           0 SETUP_LOOP              25 (to 28)
              3 LOAD_GLOBAL              0 (range)
              6 LOAD_CONST               1 (100)
              9 CALL_FUNCTION            1
             12 GET_ITER
        >>   13 FOR_ITER                11 (to 27)
             16 STORE_FAST               0 (i)
             19 LOAD_CONST               0 (None)
             22 YIELD_VALUE
             23 POP_TOP
             24 JUMP_ABSOLUTE           13
        >>   27 POP_BLOCK
        >>   28 LOAD_CONST               0 (None)
             31 RETURN_VALUE
ループの主な違いは
        >>   13 FOR_ITER                11 (to 27)
             16 STORE_FAST               0 (i)
b()対で
        >>   27 FOR_ITER                11 (to 41)
             30 STORE_DEREF              0 (i)
in a():オブジェクト (クロージャ)STORE_DEREF内のストア。(おそらく) 少し高速に動作する「通常の」変数を使用します。cellSTORE_FAST
ラムダも違いを生みます:
>>> dis.dis(lambda: i)
  1           0 LOAD_GLOBAL              0 (i)
              3 RETURN_VALUE
ここには がありますが、LOAD_GLOBAL上記のものは を使用していますLOAD_DEREF。後者も閉鎖用です。
のことをすっかり忘れていましlambda i=i: iた。
値をデフォルト パラメータとして持っている場合は、完全に異なるパスを介して関数への道を見つけます。現在の値はi、デフォルト パラメータを介して、作成したばかりの関数に渡されます。
>>> i = 42
>>> f = lambda i=i: i
>>> dis.dis(f)
  1           0 LOAD_FAST                0 (i)
              3 RETURN_VALUE
このようにして、関数は として呼び出されf()ます。欠落している引数があることを検出し、それぞれのパラメーターにデフォルト値を入力します。これはすべて、関数が呼び出される前に発生します。関数内から、値が取得されて返されることがわかります。
そして、あなたのタスクを達成するためのさらに別の方法があります: 値を取るかのようにラムダを使用するだけです: lambda i: i. これを呼び出すと、引数の欠落について文句を言います。
しかし、あなたはそれを使用して対処することができますfunctools.partial:
ff = [functools.partial(lambda i: i, x) for x in range(100)]
ff[12]()
ff[54]()
このラッパーは、callable と渡されるいくつかの引数を取得します。結果のオブジェクトは、これらの引数と指定した引数を使用して元の callable を呼び出す callable です。ここで使用して、意図した値に固定しておくことができます。