[Python-checkins] r70637 - peps/trunk/pep-0380.txt
guido.van.rossum
python-checkins at python.org
Fri Mar 27 20:33:34 CET 2009
Author: guido.van.rossum
Date: Fri Mar 27 20:33:33 2009
New Revision: 70637
Log:
New version from Greg.
Modified:
peps/trunk/pep-0380.txt
Modified: peps/trunk/pep-0380.txt
==============================================================================
--- peps/trunk/pep-0380.txt (original)
+++ peps/trunk/pep-0380.txt Fri Mar 27 20:33:33 2009
@@ -40,8 +40,8 @@
::
- for v in g:
- yield v
+ for v in g:
+ yield v
However, if the subgenerator is to interact properly with the caller
in the case of calls to ``send()``, ``throw()`` and ``close()``, things
@@ -63,7 +63,7 @@
::
- yield from <expr>
+ yield from <expr>
where <expr> is an expression evaluating to an iterable, from which an
iterator is extracted. The iterator is run to exhaustion, during which
@@ -78,30 +78,30 @@
In general, the semantics can be described in terms of the iterator
protocol as follows:
- * Any values that the iterator yields are passed directly to the
- caller.
+ * Any values that the iterator yields are passed directly to the
+ caller.
- * Any values sent to the delegating generator using ``send()``
- are passed directly to the iterator. If the sent value is None,
- the iterator's ``next()`` method is called. If the sent value is
- not None, the iterator's ``send()`` method is called. Any exception
- resulting from attempting to call ``next`` or ``send`` is raised
- in the delegating generator.
-
- * Exceptions passed to the ``throw()`` method of the delegating
- generator are forwarded to the ``throw()`` method of the iterator.
- If the iterator does not have a ``throw()`` method, its ``close()``
- method is called if it has one, then the thrown-in exception is
- raised in the delegating generator. Any exception resulting from
- attempting to call these methods (apart from one case noted below)
- is raised in the delegating generator.
-
- * The value of the ``yield from`` expression is the first argument
- to the ``StopIteration`` exception raised by the iterator when it
- terminates.
+ * Any values sent to the delegating generator using ``send()``
+ are passed directly to the iterator. If the sent value is None,
+ the iterator's ``next()`` method is called. If the sent value is
+ not None, the iterator's ``send()`` method is called. Any exception
+ resulting from attempting to call ``next`` or ``send`` is raised
+ in the delegating generator.
+
+ * Exceptions passed to the ``throw()`` method of the delegating
+ generator are forwarded to the ``throw()`` method of the iterator.
+ If the iterator does not have a ``throw()`` method, its ``close()``
+ method is called if it has one, then the thrown-in exception is
+ raised in the delegating generator. Any exception resulting from
+ attempting to call these methods (apart from one case noted below)
+ is raised in the delegating generator.
+
+ * The value of the ``yield from`` expression is the first argument
+ to the ``StopIteration`` exception raised by the iterator when it
+ terminates.
- * ``return expr`` in a generator causes ``StopIteration(expr)`` to
- be raised.
+ * ``return expr`` in a generator causes ``StopIteration(expr)`` to
+ be raised.
Fine Details
@@ -113,8 +113,9 @@
this as a request to finalize itself.
If a call to the iterator's ``throw()`` method raises a StopIteration
-exception, and it is *not* the same exception object that was thrown
-in, its value is returned as the value of the ``yield from`` expression
+exception, and it is *not* the same exception object that was thrown in,
+and the original exception was not GeneratorExit, then the value of the
+new exception is returned as the value of the ``yield from`` expression
and the delegating generator is resumed.
@@ -133,51 +134,48 @@
::
- RESULT = yield from EXPR
+ RESULT = yield from EXPR
is semantically equivalent to
::
- _i = iter(EXPR)
- try:
- try:
- _y = _i.next()
- except StopIteration, _e:
- _r = _e.value
- else:
- while 1:
- try:
- _s = yield _y
- except:
- _m = getattr(_i, 'throw', None)
- if _m is not None:
- _x = sys.exc_info()
- try:
- _y = _m(*_x)
- except StopIteration, _e:
- if _e is _x[1]:
- raise
- else:
- _r = _e.value
- break
- else:
- _m = getattr(_i, 'close', None)
- if _m is not None:
- _m()
- raise
- else:
- try:
- if _s is None:
- _y = _i.next()
- else:
- _y = _i.send(_s)
- except StopIteration, _e:
- _r = _e.value
- break
- finally:
- del _i
- RESULT = _r
+ _i = iter(EXPR)
+ try:
+ _y = _i.next()
+ except StopIteration, _e:
+ _r = _e.value
+ else:
+ while 1:
+ try:
+ _s = yield _y
+ except:
+ _m = getattr(_i, 'throw', None)
+ if _m is not None:
+ _x = sys.exc_info()
+ try:
+ _y = _m(*_x)
+ except StopIteration, _e:
+ if _e is _x[1] or isinstance(_x[1], GeneratorExit):
+ raise
+ else:
+ _r = _e.value
+ break
+ else:
+ _m = getattr(_i, 'close', None)
+ if _m is not None:
+ _m()
+ raise
+ else:
+ try:
+ if _s is None:
+ _y = _i.next()
+ else:
+ _y = _i.send(_s)
+ except StopIteration, _e:
+ _r = _e.value
+ break
+ RESULT = _r
except that implementations are free to cache bound methods for the 'next',
'send' and 'throw' methods of the iterator upon first use.
@@ -186,13 +184,13 @@
::
- return value
+ return value
is semantically equivalent to
::
- raise StopIteration(value)
+ raise StopIteration(value)
except that, as currently, the exception cannot be caught by ``except``
clauses within the returning generator.
@@ -201,14 +199,14 @@
::
- class StopIteration(Exception):
+ class StopIteration(Exception):
- def __init__(self, *args):
- if len(args) > 0:
- self.value = args[0]
- else:
- self.value = None
- Exception.__init__(self, *args)
+ def __init__(self, *args):
+ if len(args) > 0:
+ self.value = args[0]
+ else:
+ self.value = None
+ Exception.__init__(self, *args)
Rationale
@@ -249,7 +247,7 @@
The assumption made is that, in the majority of use cases, the subiterator
will not be shared. The rare case of a shared subiterator can be
-accommodated by means of a wrapper that blocks ``throw()`` and ``send()``
+accommodated by means of a wrapper that blocks ``throw()`` and ``close()``
calls, or by using a means other than ``yield from`` to call the
subiterator.
@@ -269,14 +267,14 @@
::
- y = f(x)
+ y = f(x)
where f is an ordinary function, can be transformed into a delegation
call
::
- y = yield from g(x)
+ y = yield from g(x)
where g is a generator. One can reason about the behaviour of the
resulting code by thinking of g as an ordinary function that can be
@@ -341,13 +339,13 @@
mechanism is attractive for a couple of reasons:
* Using the StopIteration exception makes it easy for other kinds
- of iterators to participate in the protocol without having to
- grow an extra attribute or a close() method.
+ of iterators to participate in the protocol without having to
+ grow an extra attribute or a close() method.
* It simplifies the implementation, because the point at which the
- return value from the subgenerator becomes available is the same
- point at which StopIteration is raised. Delaying until any later
- time would require storing the return value somewhere.
+ return value from the subgenerator becomes available is the same
+ point at which StopIteration is raised. Delaying until any later
+ time would require storing the return value somewhere.
Criticisms
More information about the Python-checkins
mailing list