1. ホーム
  2. python

[解決済み] ループの中のラムダ [重複] [重複

2023-05-22 10:13:16

質問

以下のコードスニペットを考慮する。

# directorys == {'login': <object at ...>, 'home': <object at ...>}
for d in directorys:
    self.command["cd " + d] = (lambda : self.root.change_directory(d))

私は、以下のような2つの関数の辞書を作成することを期待しています。

# Expected :
self.command == {
    "cd login": lambda: self.root.change_directory("login"),
    "cd home": lambda: self.root.change_directory("home")
}

のように見えますが、生成された2つのラムダ関数が全く同じものであるように見えます。

# Result :
self.command == {
    "cd login": lambda: self.root.change_directory("login"),
    "cd home": lambda: self.root.change_directory("login")   # <- Why login ?
}

私は本当に理由を理解していない。あなたは何か提案を持っていますか?

どのように解決するのですか?

作成した関数ごとにdをバインドする必要があります。そのための1つの方法は、デフォルト値でパラメータとして渡すことです。

lambda d=d: self.root.change_directory(d)

これで、関数内部のdは、同じ名前であってもパラメータを使用し、そのデフォルト値が関数作成時に評価されるようになりました。これを見やすくするために

lambda bound_d=d: self.root.change_directory(bound_d)

オブジェクトをバインドしているので、リストやディクスのようなミュータブルなオブジェクトの場合など、デフォルト値がどのように機能するかを覚えておいてください。

デフォルト値を持つパラメータのこのイディオムは十分に一般的ですが、関数パラメータをイントロスペクトし、その存在に基づいて何をすべきかを決定する場合、失敗する可能性があります。 別のクロージャでパラメータを回避することができます。

(lambda d=d: lambda: self.root.change_directory(d))()
# or
(lambda d: lambda: self.root.change_directory(d))(d)