0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Re: Pythonのlambdaがダメダメな^H^H^H^H^H使い方が難しい件

Posted at

@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 であるとされています。

0
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?