[Python-ideas] Revised**6 PEP on yield-from

Guido van Rossum guido at python.org
Sun Feb 22 16:57:52 CET 2009


On Sun, Feb 22, 2009 at 2:25 AM, Greg Ewing <greg.ewing at canterbury.ac.nz> wrote:
> Bruce Frederiksen wrote:
>>
>> Greg Ewing wrote:
>>       If the sent value is
>>>
>>>      not None, the iterator's ``send()`` method is called if it has
>>>      one, otherwise an exception is raised in the delegating generator.
>>
>> Shouldn't this define which exception is raised?
>
> To put it more precisely, whatever exception results from
> attempting to call the non-existent send() method is propagated
> into the delegating generator.
>
>> Intuitively, I would expect that the delegating generator would not see
>> this exception; as if the delegating generator itself lacked a send method.
>
> This would introduce an inconsistency between delegating to a
> generator and delegating to some other kind of iterator.
>
> When delegating to another generator, the inlining principle
> requires that any exceptions raised by the subgenerator must be
> propagated through the delegating generator. This includes
> whatever exceptions might result from attempting to send values
> to the subgenerator.
>
> My feeling is that other iterators should behave the same way
> as generators, as closely as possible, when delegated to.
>
> There's also the consideration that the semantics you propose
> can't be expressed in terms of a Python expansion, since there's
> no way for a generator to throw an exception right out of itself
> without triggering any except or finally blocks on the way.

And that would be bad -- if the yield-from is inside a try/finally,
I'd expect the finally clause to be run.

> While that's not a fatal flaw, I think it's highly desirable
> to be able to specify the semantics in terms of an expansion,
> because of its precision. Currently the expansion in the PEP
> is the only precise and complete specification. It's very
> hard to express all the nuances and ramifications in words
> and be sure that you've covered everything -- as witnessed
> by your comments above!
>
>> OTOH, this may be a reason to just translate send to next for non-None
>> values too???  Perhaps the justification in that case would be to think of
>> it like sending to a yield *statement* (which can't accept the sent value)
>> -- which is not an error in generators.
>
> That's a distinct possibility. Guido pointed out that there
> is an existing case where send() refuses to accept anything
> other than None, and that's when you call it immediately
> after the generator starts.
>
> But that case doesn't apply here, because the first call to a
> delegated iterator is always made implicitly by the yield-from
> expression itself. So a send() that gets delegated to a subiterator
> is *never* the first call, and therefore it should ignore any sent
> values that it doesn't care about.
>
> In other words, go back to what I had in the first draft of
> the PEP:
>
>            if hasattr(_i, 'send'):
>                _u = _i.send(_v)
>            else:
>                _u = _i.next()
>
> or perhaps
>
>            if _v is not None and hasattr(_i, 'send'):
>                _u = _i.send(_v)
>            else:
>                _u = _i.next()
>
> Guido, what do you think about this?

I think it's all pretty academic as long as it is specified with
sufficient exactness that someone else reimplementing it will arrive
at the same choices. I don't particularly like the LBYL (Look Before
You Leap) idiom, so let's do this:

if _v is None:
  _u = _i.next()  # Or, in Py3k, _u = next(i)
else:
  _u = _i.send(_v)

This means that sending a non-None value into a generator that
delegates to a non-generator iterator will fail. I doubt there will be
too many use cases that are inconvenienced by this.

After all, the presence of a 'send' attribute doesn't mean it can be
called anyway, and even if it can, it doesn't mean the call will
succeed.

-- 
--Guido van Rossum (home page: http://www.python.org/~guido/)



More information about the Python-ideas mailing list