This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: yield in iterators
Type: behavior Stage:
Components: Interpreter Core Versions: Python 3.0, Python 3.1
process
Status: closed Resolution: wont fix
Dependencies: Superseder:
Assigned To: Nosy List: gvanrossum, pitrou, qwjqwj, terry.reedy
Priority: normal Keywords:

Created on 2009-03-27 12:25 by qwjqwj, last changed 2022-04-11 14:56 by admin. This issue is now closed.

Messages (12)
msg84257 - (view) Author: (qwjqwj) Date: 2009-03-27 12:25
In Python 3.0,3.1a1:

>>> def f():
	[(yield i) for i in range(10)]
>>> f()
>>> f() is None
True

>>> def f():
	((yield i) for i in range(10))
>>> f()
>>> f() is None
True

However it is correct in Python 2.5,2.6

>>> def f():
...     [(yield i) for i in range(10)]
... 
>>> f()
<generator object f at 0x2b84bbe3ae60>
msg84267 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2009-03-27 15:48
Perhaps you forgot to return the value. In 3.1:

>>> def f():
...  return [(yield i) for i in range(10)]
... 
>>> f()
<generator object <listcomp> at 0x7f9bcc2257d0>
msg84268 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2009-03-27 15:53
It's true, however, that there is a difference in behaviour between 2.x
and 3.x here.
In 2.x, the function containing the list comprehension is a generator.
In 3.x, it's the list comprehension itself which becomes a generator.
I'm not sure which one is more useful. Also, it's likely that this won't
be changed, because it's due to the compilation model of list
comprehensions (which are compiled as a separate code object in 3.x).
msg84270 - (view) Author: (qwjqwj) Date: 2009-03-27 16:12
Why should yield can be put inside the iterator? The behavior here is
very weired.

>>> x = [(yield i) for i in range(10)]
>>> print(list(x))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, [None, None, None, None, None, None,
None, None, None, None]]
msg84271 - (view) Author: (qwjqwj) Date: 2009-03-27 16:13
>>> x = ((yield i) for i in range(10))
>>> list(x)
[0, None, 1, None, 2, None, 3, None, 4, None, 5, None, 6, None, 7, None,
8, None, 9, None]
msg84272 - (view) Author: (qwjqwj) Date: 2009-03-27 16:14
>>> x = {(yield i) for i in range(10)}
>>> x
<generator object <setcomp> at 0x02A453F0>
>>> list(x)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, {None}]
msg84273 - (view) Author: (qwjqwj) Date: 2009-03-27 16:33
More experiments:
The tuple pair (10,20) don't correspond to (i,i*i)
The yield order is distorted

>>> x = (((yield i),(yield i*i)) for i in range(3))
>>> x.__next__()
0
>>> x.send(10)
0
>>> x.send(20)
(10, 20)
>>> x.send(30)
1
>>> x.send(40)
1
>>> x.send(60)
(40, 60)
>>> x.send(70)
2
>>> x.send(80)
4
>>> x.send(90)
(80, 90)
>>> x.send(100)
Traceback (most recent call last):
  File "<pyshell#107>", line 1, in <module>
    x.send(100)
StopIteration
msg84274 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2009-03-27 16:41
> More experiments:
> The tuple pair (10,20) don't correspond to (i,i*i)

This is normal, since it corresponds to ((yield i), (yield i*i)).
The value of a yield expression is what the caller puts into send(), not
what is yielded to the caller. And since you sent 10 then 20, the
resulting tuple is (10, 20).

> The yield order is distorted

It is quite logical actually. The generator first has to yield two
values before being able to produce a third one (the tuple consisting of
the value of two "yield" expressions).
msg84275 - (view) Author: (qwjqwj) Date: 2009-03-27 16:52
Ok, I see. Thanks.
However, I don't think yield should be consumed at the iterator's level.
It may be more useful for the outside function to consume the yield.

For example, some function want to change some data with another "thread".

def f():
    ...fetch data...
    x = [yield i for i in data]

It should be written as belowed in Python 3.1 now
def f():
    x = []
    for i in data:
        x.append((yield i))
msg84278 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2009-03-27 18:58
Can anyone think of a *reason* to put a yield inside a generator
expression?  ISTM we could just forbid this syntactically.  It seems
insane and hard to read so if someone has a reason they should write it
out using an explicit for-statement.
msg84288 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2009-03-27 23:29
I think this should just be closed.

The original implied claim that 3.0 is not correct is not correct.  The
change of behavior is a clear side effect of and intended and documented
change in the semantics of comprehensions.

As near as I can tell, the results of the experiments are all correct
according to the doc for yield.

Python-list or the python-ideas list is more appropriate than the
tracker to discuss a semantic change.  In any case, comprehensions are
function expressions, like lambda expressions, and expressions therein
should act much the same as the expression in a lambda expression.

Even if unclear, slightly insane, and not very useful, I do not think
yield should be prohibited in generators expression because
1) it would introduce a back-incompatibility in 3.1;
2) it would slightly break the parallelism with other comprehensions;
3) it would slightly break the parallelism with the expanded for-form;
4) such use is unlikely in real practice; and
5) it would raise the question of where else to prohibit yield.
msg84289 - (view) Author: Guido van Rossum (gvanrossum) * (Python committer) Date: 2009-03-27 23:30
Fine!
History
Date User Action Args
2022-04-11 14:56:47adminsetgithub: 49827
2009-03-27 23:30:50gvanrossumsetstatus: open -> closed
resolution: wont fix
messages: + msg84289
2009-03-27 23:29:10terry.reedysetnosy: + terry.reedy
messages: + msg84288
2009-03-27 18:58:28gvanrossumsetnosy: + gvanrossum
messages: + msg84278
2009-03-27 16:52:21qwjqwjsetmessages: + msg84275
2009-03-27 16:41:37pitrousetmessages: + msg84274
2009-03-27 16:33:26qwjqwjsetmessages: + msg84273
2009-03-27 16:14:44qwjqwjsetmessages: + msg84272
2009-03-27 16:13:02qwjqwjsetmessages: + msg84271
2009-03-27 16:12:11qwjqwjsetmessages: + msg84270
2009-03-27 15:53:33pitrousetmessages: + msg84268
2009-03-27 15:48:52pitrousetnosy: + pitrou
messages: + msg84267
2009-03-27 12:25:13qwjqwjcreate