[解決済み】ラムダ関数のクロージャは何を捕捉するのか?
質問
最近、Pythonをいじり始めて、クロージャの動作に奇妙なことに気がつきました。以下のコードを考えてみてください。
adders=[None, None, None, None]
for i in [0,1,2,3]:
adders[i]=lambda a: i+a
print adders[1](3)
これは、一つの入力を受け取り、その入力に数値を加えて返す関数の簡単な配列を構築する。この関数は
for
ループで、イテレータ
i
から実行されます。
0
から
3
. これらの各数値に対して
lambda
をキャプチャする関数が作成されます。
i
を作成し、この関数の入力に追加します。最後の行では、2番目の
lambda
関数に
3
をパラメータとする。驚いたことに、出力は
6
.
を期待したのですが
4
. 私の理由は、Pythonではすべてがオブジェクトであり、したがってすべての変数はそれへのポインタであることが不可欠だからです。そのため
lambda
のクロージャは
i
が現在指している整数オブジェクトへのポインタを格納すると思っていました。
i
. つまり
i
に新しい整数オブジェクトを割り当てても、以前に作成したクロージャに影響を与えないはずです。悲しいことに
adders
の配列は、デバッガで見ると、そのように見える。すべて
lambda
の最後の値を参照します。
i
,
3
となり、その結果
adders[1](3)
を返します。
6
.
ということが気になりますね。
- クロージャは具体的に何を捕捉するのか?
-
を納得させる最もエレガントな方法は何でしょうか?
lambda
の現在値を取得するための関数です。i
を実行したときに影響を受けないような方法でi
は、その値を変更するのですか?
解決方法は?
2つ目の質問については回答済みですが、1つ目の質問については。
クロージャは具体的に何を捕らえるのでしょうか?
Pythonのスコーピングは <ストライク ダイナミックで レキシカルです。クロージャは常に変数の名前とスコープを記憶し、それが指しているオブジェクトは記憶しません。この例では、すべての関数が同じスコープで作成され、同じ変数名を使用しているので、常に同じ変数を参照していることになります。
もう一つの質問である、これを克服する方法についてですが、思い当たるのは2つの方法です。
-
最も簡潔な方法ですが、厳密には同等ではありません。 Adrien Plisson が推奨する . ラムダを追加で作成し、その追加引数のデフォルト値を保存したいオブジェクトに設定します。
-
もう少し冗長ですが、ラムダを作成するたびに新しいスコープを作成する方が簡単でしょう。
>>> adders = [0,1,2,3] >>> for i in [0,1,2,3]: ... adders[i] = (lambda b: lambda a: b + a)(i) ... >>> adders[1](3) 4 >>> adders[2](3) 5
ここでのスコープは、引数を束ねる新しい関数(簡潔にするためにラムダ)を使って作成し、束ねたい値を引数として渡しています。しかし、実際のコードでは、ラムダの代わりに普通の関数を使って新しいスコープを作成することがほとんどです。
def createAdder(x):
return lambda y: y + x
adders = [createAdder(i) for i in range(4)]
関連
-
Python カメの描画コマンドとその例
-
[解決済み】ImportError: sklearn.cross_validation という名前のモジュールがない。
-
[解決済み】Flaskのテンプレートが見つからない【重複あり
-
[解決済み] 関数内でグローバル変数を使用する
-
[解決済み] __init__.py は何のためにあるのですか?
-
[解決済み] クロージャ」と「ラムダ」の違いは何ですか?
-
[解決済み】if __name__ == "__main__": は何をするのでしょうか?
-
[解決済み】__str__と__repr__の違いは何ですか?
-
[解決済み】C++11のラムダ式って何?
-
[解決済み】JavaScriptのクロージャと無名関数の比較
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
pythonサイクルタスクスケジューリングツール スケジュール詳解
-
風力制御におけるKS原理を深く理解するためのpythonアルゴリズム
-
PythonによるExcelファイルの一括操作の説明
-
[解決済み】RuntimeWarning: invalid value encountered in double_scalars で numpy の除算ができない。
-
[解決済み】ImportError: sklearn.cross_validation という名前のモジュールがない。
-
[解決済み】numpy: true_divide で無効な値に遭遇
-
[解決済み】TypeError: re.findall()でバイトのようなオブジェクトに文字列パターンを使用することはできません。)
-
[解決済み] builtins.TypeError: strでなければならない、bytesではない
-
[解決済み】Python: OverflowError: 数学の範囲エラー
-
[解決済み】 TypeError: += でサポートされていないオペランド型: 'int' および 'list' です。