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