[Python-ideas] Using yield inside a comprehension.

Andrew Barnert abarnert at yahoo.com
Tue Nov 26 15:55:20 CET 2013


On Nov 26, 2013, at 6:32, Oscar Benjamin <oscar.j.benjamin at gmail.com> wrote:

> On 26 November 2013 13:54, Jonathan Slenders <jonathan at slenders.be> wrote:
>> 
>> Where do I find the PEP that describes that the following statement assigns
>> a generator object to `values`?
> 
> I don't think there was a PEP for this but it's a consequence of the
> change to binding in list comprehensions introduced in Python 3.x
> which is mentioned here:
> http://python-history.blogspot.co.uk/2010/06/from-list-comprehensions-to-generator.html
> 
> Essentially this:
> 
>> values = [ (yield x) for x in range(10) ]
> 
> Translates to the following in Python 2.x:
> 
> _tmp = []
> for x in range(10):
>    _tmp.append((yield x))
> values = _tmp
> 
> However in 3.x it translates to something like:
> 
> def _tmpfunc():
>    _tmp = []
>    for x in range(10):
>        _tmp.append((yield x))
>    return _tmp
> values = _tmpfunc()
> 
> This change was made to prevent the comprehension variable from
> leaking to the enclosing scope, but as you say if the code is nested
> in a function then it affects which function contains the yield
> statement and the presence of a yield statement radically alters the
> behaviour of a function. So in 2.x the enclosing function must become
> a generator function. However in 3.x the function that is supposed to
> implement the list comprehension is changed into a generator function
> instead.
> 
> $ python3
> Python 3.3.2 (v3.3.2:d047928ae3f6, May 16 2013, 00:03:43) [MSC v.1600
> 32 bit (Intel)] on win32
> Type "help", "copyright", "credits" or "license" for more information.
>>>> values = [(yield x) for x in range(10)]
>>>> values
> <generator object <listcomp> at 0x00E24508>
>>>> def _tmpfunc():
> ...     _tmp = []
> ...     for x in range(10):
> ...         _tmp.append((yield x))
> ...     return _tmp
> ...
>>>> values = _tmpfunc()
>>>> values
> <generator object _tmpfunc at 0x00E2F7B0>
> 
>> I assume it's equivalent to the following:
>> values = (x for x in range(10))
> 
> It will yield the same values but it will also build a list of Nones
> and attach it to StopIteration:

Unless you call .send on it, in which case it'll build a list of the values you send it and attach _that_ to StopIteration, of course.

So I suppose you could use it as a coroutine version of the list function. Except that the number of values it takes is specified on the wrong end.


More information about the Python-ideas mailing list