More clarifications in response to Oscar Benjamin.

This commit is contained in:
Guido van Rossum 2014-12-11 11:02:14 -08:00
parent b142f8f22d
commit 4af42e2b28
1 changed files with 24 additions and 4 deletions

View File

@ -43,13 +43,16 @@ The interaction of generators and ``StopIteration`` is currently
somewhat surprising, and can conceal obscure bugs. An unexpected
exception should not result in subtly altered behaviour, but should
cause a noisy and easily-debugged traceback. Currently,
``StopIteration`` can be absorbed by the generator construct.
``StopIteration`` raised accidentally inside a generator function will
be interpreted as the end of the iteration by the loop construct
driving the generator.
The main goal of the proposal is to ease debugging in the situation
where an unguarded ``next()`` call (perhaps several stack frames deep)
raises ``StopIteration`` and causes the iteration controlled by the
generator to terminate silently. (When another exception is raised, a
traceback is printed pinpointing the cause of the problem.)
generator to terminate silently. (Whereas, when some other exception
is raised, a traceback is printed pinpointing the cause of the
problem.)
This is particularly pernicious in combination with the ``yield from``
construct of PEP 380 [1]_, as it breaks the abstraction that a
@ -352,7 +355,9 @@ iterators: a generator object is still an iterator, and not all
iterators are generators. Generators have additional methods that
iterators don't have, like ``send`` and ``throw``. All this is
unchanged. Nothing changes for generator users -- only authors of
generator functions may have to learn something new.
generator functions may have to learn something new. (This includes
authors of generator expressions that depend on early termination of
the iteration by a ``StopIteration`` raised in a condition.)
An iterator is an object with a ``__next__`` method. Like many other
special methods, it may either return a value, or raise a specific
@ -489,6 +494,10 @@ block of code which reliably works on multiple versions of Python.
(Using a dedicated exception type, perhaps subclassing ``ValueError``,
would help this; however, all code would still need to be rewritten.)
Note that calling ``next(it, default)`` catches ``StopIteration`` and
substitutes the given default value; this feature is often useful to
avoid a ``try/except`` block.
Sub-proposal: decorator to explicitly request current behaviour
---------------------------------------------------------------
@ -556,6 +565,17 @@ their return paths, they too could turn unexpected exceptions into
``RuntimeError``; the fact that they cannot should not preclude
generators from doing so.
Why not fix all __next__() methods?
-----------------------------------
When implementing a regular ``__next__()`` method, the only way to
indicate the end of the iteration is to raise ``StopIteration``. So
catching ``StopIteration`` here and converting it to ``RuntimeError``
would defeat the purpose. This is a reminder of the special status of
generator functions: in a generator function, raising
``StopIteration`` is redundant since the iteration can be terminated
by a simple ``return``.
References
==========