Update PEP 479 from author.
This commit is contained in:
parent
4dfd824041
commit
66080c2e52
62
pep-0479.txt
62
pep-0479.txt
|
@ -29,15 +29,27 @@ cause a noisy and easily-debugged traceback. Currently,
|
|||
``StopIteration`` can be absorbed by the generator construct.
|
||||
|
||||
|
||||
Background information
|
||||
======================
|
||||
|
||||
When a generator frame is (re)started as a result of a ``__next__()``
|
||||
(or ``send()`` or ``throw()``) call, one of three outcomes can occur:
|
||||
|
||||
* A yield point is reached, and the yielded value is returned.
|
||||
* The frame is returned from; ``StopIteration`` is raised.
|
||||
* An exception is thrown, which bubbles out.
|
||||
|
||||
|
||||
Proposal
|
||||
========
|
||||
|
||||
If a ``StopIteration`` is about to bubble out of a generator frame, it
|
||||
is replaced with some other exception (maybe ``RuntimeError``, maybe a
|
||||
new custom ``Exception`` subclass, but *not* deriving from
|
||||
``StopIteration``) which causes the ``next()`` call (which invoked the
|
||||
generator) to fail, passing that exception out. From then on it's
|
||||
just like any old exception. [3]_
|
||||
is replaced with ``RuntimeError``, which causes the ``next()`` call
|
||||
(which invoked the generator) to fail, passing that exception out.
|
||||
From then on it's just like any old exception. [3]_
|
||||
|
||||
This affects the third outcome listed above, without altering any
|
||||
other effects.
|
||||
|
||||
|
||||
Consequences to existing code
|
||||
|
@ -56,19 +68,38 @@ yield from helper()" rather than just "helper()".""")
|
|||
|
||||
As this can break code, it is proposed to utilize the ``__future__``
|
||||
mechanism to introduce this, finally making it standard in Python 3.6
|
||||
or 3.7.
|
||||
or 3.7. Any generator function constructed in the presence of this
|
||||
directive will have a flag set on its code object, and generators with
|
||||
the flag set will behave according to this proposal. Once the feature
|
||||
becomes standard, the flag may be dropped; code should not inspect
|
||||
generators for it. (GvR: """And the flag should somehow be
|
||||
transferred to the stack frame when the function is executed, so the
|
||||
right action can be taken when an exception is about to bubble out of
|
||||
that frame.""")
|
||||
|
||||
|
||||
Alternate proposals
|
||||
===================
|
||||
|
||||
Raising something other than RuntimeError
|
||||
-----------------------------------------
|
||||
|
||||
Rather than the generic ``RuntimeError``, it might make sense to raise
|
||||
a new exception type ``UnexpectedStopIteration``. This has the
|
||||
downside of implicitly encouraging that it be caught; the correct
|
||||
action is to catch the original ``StopIteration``, not the chained
|
||||
exception.
|
||||
|
||||
|
||||
Supplying a specific exception to raise on return
|
||||
-------------------------------------------------
|
||||
|
||||
Nick Coghlan suggested a means of providing a specific
|
||||
``StopIteration`` instance to the generator; if any other instance of
|
||||
``StopIteration`` is raised, it is an error, but if that particular
|
||||
one is raised, the generator has properly completed.
|
||||
one is raised, the generator has properly completed. This subproposal
|
||||
has been withdrawn in favour of better options, but is retained for
|
||||
reference.
|
||||
|
||||
|
||||
Making return-triggered StopIterations obvious
|
||||
|
@ -80,6 +111,23 @@ raising ``StopIteration``, it raises a specific subclass of
|
|||
``StopIteration`` which can then be detected. If it is not that
|
||||
subclass, it is an escaping exception rather than a return statement.
|
||||
|
||||
Of the three outcomes listed above:
|
||||
|
||||
* A yielded value, obviously, would still be returned.
|
||||
* If the frame is returned from, ``GeneratorReturn`` is raised.
|
||||
* If an instance of ``GeneratorReturn`` would be raised, instead an
|
||||
instance of ``StopIteration`` would be raised.
|
||||
|
||||
In the third case, the ``StopIteration`` would have the ``value`` of
|
||||
the original ``GeneratorReturn``, and would reference the original
|
||||
exception in its ``__cause__``. If uncaught, this would clearly show
|
||||
the chaining of exceptions.
|
||||
|
||||
This does *not* affect the discrepancy between generator expressions
|
||||
and list comprehensions, but allows generator-aware code (such as the
|
||||
contextlib and asyncio modules) to reliably differentiate between the
|
||||
second and third outcomes listed above.
|
||||
|
||||
|
||||
Criticism
|
||||
=========
|
||||
|
|
Loading…
Reference in New Issue