◐ Shell
clean mode source ↗

Issue 3267: yield in list comprehensions possibly broken in 3.0

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 "<stdin>", line 1, in <module>
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 <listcomp> at 0x3678f0>
>>> x.send(7)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
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 <listcomp> at
0x740770, file "<stdin>", 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