New version from Greg.
This commit is contained in:
parent
eb61d88000
commit
dcbd51055b
162
pep-0380.txt
162
pep-0380.txt
|
@ -40,8 +40,8 @@ much difficulty using a loop such as
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
for v in g:
|
for v in g:
|
||||||
yield v
|
yield v
|
||||||
|
|
||||||
However, if the subgenerator is to interact properly with the caller
|
However, if the subgenerator is to interact properly with the caller
|
||||||
in the case of calls to ``send()``, ``throw()`` and ``close()``, things
|
in the case of calls to ``send()``, ``throw()`` and ``close()``, things
|
||||||
|
@ -63,7 +63,7 @@ generator:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
yield from <expr>
|
yield from <expr>
|
||||||
|
|
||||||
where <expr> is an expression evaluating to an iterable, from which an
|
where <expr> is an expression evaluating to an iterable, from which an
|
||||||
iterator is extracted. The iterator is run to exhaustion, during which
|
iterator is extracted. The iterator is run to exhaustion, during which
|
||||||
|
@ -78,30 +78,30 @@ becomes the value of the ``yield from`` expression.
|
||||||
In general, the semantics can be described in terms of the iterator
|
In general, the semantics can be described in terms of the iterator
|
||||||
protocol as follows:
|
protocol as follows:
|
||||||
|
|
||||||
* Any values that the iterator yields are passed directly to the
|
* Any values that the iterator yields are passed directly to the
|
||||||
caller.
|
caller.
|
||||||
|
|
||||||
* Any values sent to the delegating generator using ``send()``
|
* Any values sent to the delegating generator using ``send()``
|
||||||
are passed directly to the iterator. If the sent value is None,
|
are passed directly to the iterator. If the sent value is None,
|
||||||
the iterator's ``next()`` method is called. If the sent value is
|
the iterator's ``next()`` method is called. If the sent value is
|
||||||
not None, the iterator's ``send()`` method is called. Any exception
|
not None, the iterator's ``send()`` method is called. Any exception
|
||||||
resulting from attempting to call ``next`` or ``send`` is raised
|
resulting from attempting to call ``next`` or ``send`` is raised
|
||||||
in the delegating generator.
|
in the delegating generator.
|
||||||
|
|
||||||
* Exceptions passed to the ``throw()`` method of the delegating
|
* Exceptions passed to the ``throw()`` method of the delegating
|
||||||
generator are forwarded to the ``throw()`` method of the iterator.
|
generator are forwarded to the ``throw()`` method of the iterator.
|
||||||
If the iterator does not have a ``throw()`` method, its ``close()``
|
If the iterator does not have a ``throw()`` method, its ``close()``
|
||||||
method is called if it has one, then the thrown-in exception is
|
method is called if it has one, then the thrown-in exception is
|
||||||
raised in the delegating generator. Any exception resulting from
|
raised in the delegating generator. Any exception resulting from
|
||||||
attempting to call these methods (apart from one case noted below)
|
attempting to call these methods (apart from one case noted below)
|
||||||
is raised in the delegating generator.
|
is raised in the delegating generator.
|
||||||
|
|
||||||
* The value of the ``yield from`` expression is the first argument
|
* The value of the ``yield from`` expression is the first argument
|
||||||
to the ``StopIteration`` exception raised by the iterator when it
|
to the ``StopIteration`` exception raised by the iterator when it
|
||||||
terminates.
|
terminates.
|
||||||
|
|
||||||
* ``return expr`` in a generator causes ``StopIteration(expr)`` to
|
* ``return expr`` in a generator causes ``StopIteration(expr)`` to
|
||||||
be raised.
|
be raised.
|
||||||
|
|
||||||
|
|
||||||
Fine Details
|
Fine Details
|
||||||
|
@ -113,8 +113,9 @@ An iterator having a ``throw()`` method is expected to recognize
|
||||||
this as a request to finalize itself.
|
this as a request to finalize itself.
|
||||||
|
|
||||||
If a call to the iterator's ``throw()`` method raises a StopIteration
|
If a call to the iterator's ``throw()`` method raises a StopIteration
|
||||||
exception, and it is *not* the same exception object that was thrown
|
exception, and it is *not* the same exception object that was thrown in,
|
||||||
in, its value is returned as the value of the ``yield from`` expression
|
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.
|
and the delegating generator is resumed.
|
||||||
|
|
||||||
|
|
||||||
|
@ -133,51 +134,48 @@ Formal Semantics
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
RESULT = yield from EXPR
|
RESULT = yield from EXPR
|
||||||
|
|
||||||
is semantically equivalent to
|
is semantically equivalent to
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
_i = iter(EXPR)
|
_i = iter(EXPR)
|
||||||
try:
|
try:
|
||||||
try:
|
_y = _i.next()
|
||||||
_y = _i.next()
|
except StopIteration, _e:
|
||||||
except StopIteration, _e:
|
_r = _e.value
|
||||||
_r = _e.value
|
else:
|
||||||
else:
|
while 1:
|
||||||
while 1:
|
try:
|
||||||
try:
|
_s = yield _y
|
||||||
_s = yield _y
|
except:
|
||||||
except:
|
_m = getattr(_i, 'throw', None)
|
||||||
_m = getattr(_i, 'throw', None)
|
if _m is not None:
|
||||||
if _m is not None:
|
_x = sys.exc_info()
|
||||||
_x = sys.exc_info()
|
try:
|
||||||
try:
|
_y = _m(*_x)
|
||||||
_y = _m(*_x)
|
except StopIteration, _e:
|
||||||
except StopIteration, _e:
|
if _e is _x[1] or isinstance(_x[1], GeneratorExit):
|
||||||
if _e is _x[1]:
|
raise
|
||||||
raise
|
else:
|
||||||
else:
|
_r = _e.value
|
||||||
_r = _e.value
|
break
|
||||||
break
|
else:
|
||||||
else:
|
_m = getattr(_i, 'close', None)
|
||||||
_m = getattr(_i, 'close', None)
|
if _m is not None:
|
||||||
if _m is not None:
|
_m()
|
||||||
_m()
|
raise
|
||||||
raise
|
else:
|
||||||
else:
|
try:
|
||||||
try:
|
if _s is None:
|
||||||
if _s is None:
|
_y = _i.next()
|
||||||
_y = _i.next()
|
else:
|
||||||
else:
|
_y = _i.send(_s)
|
||||||
_y = _i.send(_s)
|
except StopIteration, _e:
|
||||||
except StopIteration, _e:
|
_r = _e.value
|
||||||
_r = _e.value
|
break
|
||||||
break
|
RESULT = _r
|
||||||
finally:
|
|
||||||
del _i
|
|
||||||
RESULT = _r
|
|
||||||
|
|
||||||
except that implementations are free to cache bound methods for the 'next',
|
except that implementations are free to cache bound methods for the 'next',
|
||||||
'send' and 'throw' methods of the iterator upon first use.
|
'send' and 'throw' methods of the iterator upon first use.
|
||||||
|
@ -186,13 +184,13 @@ except that implementations are free to cache bound methods for the 'next',
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
is semantically equivalent to
|
is semantically equivalent to
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
raise StopIteration(value)
|
raise StopIteration(value)
|
||||||
|
|
||||||
except that, as currently, the exception cannot be caught by ``except``
|
except that, as currently, the exception cannot be caught by ``except``
|
||||||
clauses within the returning generator.
|
clauses within the returning generator.
|
||||||
|
@ -201,14 +199,14 @@ clauses within the returning generator.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
class StopIteration(Exception):
|
class StopIteration(Exception):
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
if len(args) > 0:
|
if len(args) > 0:
|
||||||
self.value = args[0]
|
self.value = args[0]
|
||||||
else:
|
else:
|
||||||
self.value = None
|
self.value = None
|
||||||
Exception.__init__(self, *args)
|
Exception.__init__(self, *args)
|
||||||
|
|
||||||
|
|
||||||
Rationale
|
Rationale
|
||||||
|
@ -249,7 +247,7 @@ so to an unfactored one in all Python implementations.
|
||||||
|
|
||||||
The assumption made is that, in the majority of use cases, the subiterator
|
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
|
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
|
calls, or by using a means other than ``yield from`` to call the
|
||||||
subiterator.
|
subiterator.
|
||||||
|
|
||||||
|
@ -269,14 +267,14 @@ Using the proposed syntax, a statement such as
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
y = f(x)
|
y = f(x)
|
||||||
|
|
||||||
where f is an ordinary function, can be transformed into a delegation
|
where f is an ordinary function, can be transformed into a delegation
|
||||||
call
|
call
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
y = yield from g(x)
|
y = yield from g(x)
|
||||||
|
|
||||||
where g is a generator. One can reason about the behaviour of the
|
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
|
resulting code by thinking of g as an ordinary function that can be
|
||||||
|
@ -341,13 +339,13 @@ value of the ``close()`` call to the subgenerator. However, the proposed
|
||||||
mechanism is attractive for a couple of reasons:
|
mechanism is attractive for a couple of reasons:
|
||||||
|
|
||||||
* Using the StopIteration exception makes it easy for other kinds
|
* Using the StopIteration exception makes it easy for other kinds
|
||||||
of iterators to participate in the protocol without having to
|
of iterators to participate in the protocol without having to
|
||||||
grow an extra attribute or a close() method.
|
grow an extra attribute or a close() method.
|
||||||
|
|
||||||
* It simplifies the implementation, because the point at which the
|
* It simplifies the implementation, because the point at which the
|
||||||
return value from the subgenerator becomes available is the same
|
return value from the subgenerator becomes available is the same
|
||||||
point at which StopIteration is raised. Delaying until any later
|
point at which StopIteration is raised. Delaying until any later
|
||||||
time would require storing the return value somewhere.
|
time would require storing the return value somewhere.
|
||||||
|
|
||||||
|
|
||||||
Criticisms
|
Criticisms
|
||||||
|
|
Loading…
Reference in New Issue