例えば、0に等しいか調べる関数、...、3に等しいか調べる関数をリストにしたいとします。
preds = [ lambda n: n == 0, lambda n: n == 1, lambda n: n == 2, lambda n: n == 3 ] print preds[0](3) # False print preds[1](3) # False print preds[2](3) # False print preds[3](3) # True
こうすればもちろんいいですが、普通の感覚なら納得いかないでしょう。こう書くところですよね。
preds = [ lambda n: n == k for k in xrange(4) ] print preds[0](3) print preds[1](3) print preds[2](3) print preds[3](3)
これを実行すると先ほどと同じ結果が得られます。
True True True True
あ、あれ?
kが3になっているからこうなるんですねえ。ありがちです。
さて、これを回避するにはどうしたらよいでしょう。少し考えて次のようにしました。
import functools import operator preds = [ functools.partial(operator.eq, k) for k in xrange(4) ] print preds[0](3) # False print preds[1](3) # False print preds[2](3) # False print preds[3](3) # True
functools.partialは部分適用して新たな関数を作ります(正確にはpartialオブジェクトを作るらしい)。
def f(x, y): return x * 2 + y g = functools.partial(f, 1) # g(y) = 2 * 2 + y print g(3) # 5
operator.eqは
lambda x, y: x == y
と同等なので、
g = functools.partial(operator.eq, 1)
とすれば、
lambda y: 1 == y
と同等です。
これで目的は関数のリストを作ることはできました。しかし、何か腑に落ちないというか。