[Python-ideas] Revised**7 PEP on Yield-From
Jacob Holm
jh at improva.dk
Fri Mar 20 02:04:42 CET 2009
Greg Ewing wrote:
> Jacob Holm wrote:
>
>> 2. In the comment for "gen_undelegate" you mention "certain recursive
>> situations" where a generator may lose its frame before we get a
>> chance to clear f_yieldfrom. Can you elaborate?
>
> I can't remember the details, but I definitely ran into one
> during development, which is why I added that function. Have
> you tried running all of my tests?
Yup. All tests pass, except for your test19 where my traceback is
different.
> --- expected/test19.py.out 2009-02-22 09:51:26.000000000 +0100 +++
> actual/test19.py.out 2009-03-20 01:50:28.000000000 +0100 @@ -7,8 +7,8
> @@ Traceback (most recent call last): File "test19.py", line 20, in
> <module> for y in gi: - File "test19.py", line 16, in g2 - yield from
> gi File "test19.py", line 9, in g1 yield from g2() + File "test19.py",
> line 16, in g2 + yield from gi ValueError: generator already executing
I am not quite sure why that is, but I actually think mine is better.
>> 3. It looks like you are not calling "close" properly from "next",
>> "send" and "throw".
>
> I'm not sure what you mean by that. Can you provide an
> example that doesn't behave as expected?
Sure, see below.
>> 4. It looks like your "gen_close" does not try to throw a
>> GeneratorExit before calling close when delegating to a
>> non-generator.
>
> I'm not sure what you mean here either. Regardless of the
> type of sub-iterator, it should end up getting to the
> part which does
>
> if (!PyErr_Occurred())
> PyErr_SetNone(PyExc_GeneratorExit);
>
> Again, and example that doesn't behave properly would
> help.
>
Of course. Here is a demonstration/test...
class iterator(object):
"""Simple iterator that counts to n while writing what is done to it"""
def __init__(self, n):
self.ctr = iter(xrange(n))
def __iter__(self):
return self
def close(self):
print "Close"
def next(self):
print "Next"
return self.ctr.next()
def send(self, val):
print "Send", val
return self.ctr.next()
def throw(self, *args):
print "Throw:", args
return self.ctr.next()
def generator(n):
yield from iterator(n)
g = generator(1)
g.next()
try:
g.next()
except Exception, e:
print type(e)
else:
print 'No exception'
del g
print '--'
g = generator(1)
g.next()
try:
g.send(1)
except Exception, e:
print type(e)
else:
print 'No exception'
del g
print '--'
g = generator(1)
g.next()
try:
g.throw(ValueError)
except Exception, e:
print type(e)
else:
print 'No exception'
del g
print '--'
g = generator(2)
g.next()
try:
g.next()
except Exception, e:
print type(e)
else:
print 'No exception'
del g
print '--'
g = generator(2)
g.next()
try:
g.send(1)
except Exception, e:
print type(e)
else:
print 'No exception'
del g
print '--'
g = generator(2)
g.next()
try:
g.throw(ValueError)
except Exception, e:
print type(e)
else:
print 'No exception'
del g
print '--'
And here is the output I would expect based on the relevant PEPs.
Next
Next
Close
<type 'exceptions.StopIteration'>
--
Next
Send 1
Close
<type 'exceptions.StopIteration'>
--
Next
Throw: (<type 'exceptions.ValueError'>,)
Close
<type 'exceptions.StopIteration'>
--
Next
Next
No exception
Throw: (<type 'exceptions.GeneratorExit'>,)
Close
--
Next
Send 1
No exception
Throw: (<type 'exceptions.GeneratorExit'>,)
Close
--
Next
Throw: (<type 'exceptions.ValueError'>,)
No exception
Throw: (<type 'exceptions.GeneratorExit'>,)
Close
--
However, when I run this using your patch, the first 3 "Close" messages,
and the 3 "GeneratorExit" messages are missing.
Did that help?
- Jacob
More information about the Python-ideas
mailing list