[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