lambda generator - curious behavior in 2.5

Gabriel Genellina gagsl-py2 at yahoo.com.ar
Sat Apr 21 06:49:03 EDT 2007


En Sat, 21 Apr 2007 06:21:00 -0300, Boris Borcic <bborcic at gmail.com>  
escribió:

>  >>> x = (lambda : ((yield 666),(yield 777),(yield 888)))()
>  >>> x.next()
> 666
>  >>> x.next()
> 777
>  >>> x.next()
> 888
>  >>> x.next()
> (None, None, None)

I think nobody thought in advance this case (a lambda expression with  
yield?), else it would have been forbidden. The lambda is roughly  
equivalent to:

def anonymous():
   return ((yield 666),(yield 777),(yield 888))
x = anonymous()

but *that* function is forbidden: a generator cannot contain a "return  
something" statement. Writing it as a lambda expression, you are bypassing  
the compiler check.
Those three None are the 3 yield values, combined into one tuple. You can  
verify using send instead of next; the Nones are replaced by the received  
values:

py> x = (lambda : ((yield 666),(yield 777),(yield 888)))()
py> x.send(None)
666
py> x.send(1)
777
py> x.send(2)
888
py> x.send(3)
(1, 2, 3)

That was the return in effect. As the function (or lambda) is exited, the  
next try should raise StopIteration:

py> x.send(4)
Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
StopIteration

Let's check with dis:

py> dis.dis(x.gi_frame.f_code)
   1           0 LOAD_CONST               0 (666)
               3 YIELD_VALUE
               4 LOAD_CONST               1 (777)
               7 YIELD_VALUE
               8 LOAD_CONST               2 (888)
              11 YIELD_VALUE
              12 BUILD_TUPLE              3
              15 RETURN_VALUE



>  >>> x = (lambda : ((yield 666),(yield 777),(yield 888)) and None)()
>  >>> x.next()
> 666
>  >>> x.next()
> 777
>  >>> x.next()
> 888
>  >>> x.next()
>
> Traceback (most recent call last):
>    File "<pyshell#29>", line 1, in <module>
>      x.next()
> StopIteration
>  >>>

This time, the ((tuple) and None) is like saying "discard the tuple and  
return None instead", and that fires the usual StopIteration.

-- 
Gabriel Genellina




More information about the Python-list mailing list