Issue 3267: yield in list comprehensions possibly broken in 3.0 (original) (raw)
This may be a known consequence of python 3.0, but I couldn't find any reference to it, nor a test case that covers it. Here's a valid use of yield in 2.5.1:
def foo(): ... x=[(yield x) for x in 1,2,3] ... yield 5 ... yield x x=foo() x.next() 1 x.send(6) 2 x.send(7) 3 x.send(8) 5 x.send(9) [6, 7, 8] x.send(10) Traceback (most recent call last): File "", line 1, in StopIteration
But in python 3.0, this code results in:
def foo(): ... x=[(yield x) for x in (1,2,3)] ... yield 5 ... yield x x=foo() next(x) 5 x.send(6) <generator object at 0x3678f0> x.send(7) Traceback (most recent call last): File "", line 1, in StopIteration
Looking further, it seems that this is a comprehension:
def foo(): [(yield 5)] type(foo()) <class 'generator'>
Whereas this is not:
def foo(): [(yield 5) for x in range(3)] type(foo()) <class 'NoneType'>
Is this expected behavior?
This is because list comprehensions are implemented as functions in 3.0 so their scope is not leaked out to the rest of the function.
Here is the bytecode for 2.6:
dis.dis(f) 2 0 BUILD_LIST 0 3 DUP_TOP
4 STORE_FAST 0 ([1]) 7 LOAD_CONST 5 ((1, 2, 3)) 10 GET_ITER
11 FOR_ITER 14 (to 28) 14 STORE_FAST 1 (x) 17 LOAD_FAST 0 ([1]) 20 LOAD_FAST 1 (x) 23 YIELD_VALUE
24 LIST_APPEND
25 JUMP_ABSOLUTE 11 28 DELETE_FAST 0 (_[1]) 31 STORE_FAST 1 (x)
3 34 LOAD_CONST 4 (5)
37 YIELD_VALUE
38 POP_TOP
4 39 LOAD_FAST 1 (x)
42 YIELD_VALUE
43 POP_TOP
44 LOAD_CONST 0 (None)
47 RETURN_VALUE
and here it is for 3.0:
dis.dis(f) 2 0 LOAD_CONST 1 (<code object at 0x740770, file "", line 2>) 3 MAKE_FUNCTION 0 6 LOAD_CONST 6 ((1, 2, 3)) 9 GET_ITER
10 CALL_FUNCTION 1 13 STORE_FAST 0 (x)
3 16 LOAD_CONST 5 (5)
19 YIELD_VALUE
20 POP_TOP
4 21 LOAD_FAST 0 (x)
24 YIELD_VALUE
25 POP_TOP
26 LOAD_CONST 0 (None)
29 RETURN_VALUE