[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