[Python-ideas] Allow lambda decorators
Ron Adam
rrr at ronadam.com
Mon Feb 9 15:32:46 CET 2009
Carl Johnson wrote:
> A few months back there was a discussion of how code like this gives
> "surprising" results because of the scoping rules:
>
> >>> def func_maker():
> ... fs = []
> ... for i in range(10):
> ... def f():
> ... return i
> ... fs.append(f)
> ... return fs
> ...
> >>> [f() for f in func_maker()]
> [9, 9, 9, 9, 9, 9, 9, 9, 9, 9]
>
> Various syntax changes were proposed to get around this, but nothing
> ever came of it.
This isn't really a scoping rule problem. It occurs because the value of i
in f() isn't evaluated until f is called, which is after the loop is
finished.
>>> funcs = [lambda i=i:i for i in range(10)]
>>> [f() for f in funcs]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Here i's default value is set at the time f() is defined, so it avoids the
issue.
ra at Gutsy:~$ python
Python 2.5.2 (r252:60911, Oct 5 2008, 19:29:17)
[GCC 4.3.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> def f(): return i
...
>>>
Notice that we can define a function with an i variable even before i
exists. The requirement is that i exists when the function f is called.
Another way to do this is to use a proper objective approach.
>>> class obj(object):
... def __init__(self):
... self.i = i
... def __call__(self):
... return self.i
...
>>> objs = [obj() for i in range(10)]
>>> [v() for v in objs]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Because the value is stored on the object at the time the object is
created, vs when it is called, this works as expected.
For clarity and readability, I would change the __init__ line to accept a
proper argument for i, but as you see it still works.
Cheers,
Ron
More information about the Python-ideas
mailing list