Pythonでクロージャの列を作る

Pythonで lambda を使ってクロージャの列を作りたいときって、例えばCRFの素性を書くときとかによくあるよね?
でも以下のように書くと、クロージャの中の label が全部同じ値になってしまってハマる。

# A, B, C のそれぞれと一致するかどうか判定する列を作りたい
labels = ["A", "B", "C"]
features = [lambda y: 1 if y == label else 0 for label in labels]

# 全部 "C" になってる!
print features[0]("C") # => 1
print features[1]("C") # => 1
print features[2]("C") # => 1

これはクロージャの中での名前解決で無ければ上の環境を見に行くようになっているので、結局同じスコープの label (=ループの最終カウンタ) を参照してしまうため。
2重の labmda でくるんでスコープを分ける手もあるけど、煩雑で読みにくくなる。
西尾さんにデフォルト引数を使うちょっとだけいい方法を教えてもらった。

labels = ["A", "B", "C"]
features = [lambda y, l=label: 1 if y == l else 0 for label in labels]
#                     ^^^^^^^ デフォルト引数で渡して、それを使う

print features[0]("A") # => 1
print features[1]("B") # => 1
print features[2]("C") # => 1

ポイントは、Python ではデフォルト引数が関数の定義時に(従って一度だけ)評価されるということ。
そのせいで以下のようなハマりパターンもあるので、注意。

def hoge(a=[]): 
    a.append(1) 
    return a 

print hoge() # => [1] 
print hoge() # => [1, 1] 

どっちにせよ裏技的になっちゃうから、こういうコードを書かないのが本当は一番いいんだけどね。