無名関数のリストのうち一つを呼び出す無名関数のリストの混乱しやすい挙動
python2.5でGUIのプログラムをしているときにうまく動かないコードがあったので抽出して実行させたら原因が分かった。
混乱しやすいので、たしかpython3では改善されていたはず。多分。適当。
fs = [lambda: 1, lambda: 2, lambda: 3] gs = [lambda: f() for f in fs] print gs # => [<function <lambda> at 0x6b2f0>, <function <lambda> at 0x6b370>, <function <lambda> at 0x6b3b0>] print [g() for g in gs] # expect [1,2,3] # => [3, 3, 3] # ?! gs = [lambda: fs[i] for i in xrange(len(fs))] print [g() for g in gs] # # => [3, 3, 3] # ... # なぜこんな挙動に? # lambda: f()は呼び出し時にfを解決する、ということは[g() for g in gs] # を評価するときに初めてfを評価する。このときfはfsの最後の要素になっ # ているので、3回の呼び出しで常に同じ関数が呼び出されてしまう。 # また、lambda: fs[i]の場合iが実行時に評価されるので結局さっきと同様 # 常に同じ関数が呼び出される。 # # ならば、呼び出す関数の添字iをリストの評価時に与えてやればうまく動くはず。 gs = [(lambda i: lambda: fs[i]())(i) for i in xrange(len(fs))] print [g() for g in gs] # => [1, 2, 3] # ビンゴ!