[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