@buchio さんの書かれた Pythonのlambdaがダメダメな^H^H^H^H^H使い方が難しい件 という記事に反応してみます。
どうしてこうなったか
ローカル変数はその裏で領域が確保されていると考えると理解しやすいと思います。 lambda 内で参照しているのは(定義時点で見えている)変数の値そのものではなく領域です。つまり、元記事の test1 は以下のコードと等価です。
>>> def test1_aux():
... env = [None]
... funcs = []
... for i in range(10):
... env[0] = i
... funcs.append(lambda a: a+env[0])
... return funcs
...
>>> print [f(10) for f in test1_aux()]
[19, 19, 19, 19, 19, 19, 19, 19, 19, 19]
変数 i のスコープが for 文の内部に限定されていないのは確かに若干分かりにくい挙動ですが、それ以外は特におかしなところはないと思います。
ちなみに、 for 文と関係の深いリスト内包表記については、 Python 3 からは変数を外側のスコープからは参照できないようになりました。
python2
>>> [x for x in range(3)]
[0, 1, 2]
>>> x
2
python3
>>> [x for x in range(3)]
[0, 1, 2]
>>> x
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
どうすればよかったか
Python では任意のクラスで __call__ メソッドを実装すると呼び出し可能になります。そのため、クロージャーが必要なところでオブジェクトを使えばいいです。
>>> class Adder(object):
... def __init__(self, i):
... self.i = i
... def __call__(self, a):
... return a + self.i
...
>>> def test_callable():
... funcs = []
... for i in range(10):
... funcs.append(Adder(i))
... return funcs
...
>>> print [f(10) for f in test_callable()]
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
Python では、関数やオブジェクトを使った方が可読性が高くシンプルになりやすいことから、単純な式以外では lambda を使わない方がより Pythonic であるとされています。