diff --git Doc/library/exceptions.rst Doc/library/exceptions.rst index ca8e4d8..bf04b7d 100644 --- Doc/library/exceptions.rst +++ Doc/library/exceptions.rst @@ -250,8 +250,15 @@ The following exceptions are the exceptions that are usually raised. .. exception:: StopIteration Raised by built-in function :func:`next` and an :term:`iterator`\'s - :meth:`__next__` method to signal that there are no further values. - + :obj:`~iterator.__next__` method to signal that there are no + further items in the sequence. + + The exception object has a single attribute :attr:`value`, which is + given as an argument when constructing the exception, and defaults + to :const:`None`. When a generator function returns, a + :exc:`StopIteration` is raised, and the value returned by the + function is used as the :attr:`value` parameter to the constructor + of the exception. .. exception:: SyntaxError diff --git Doc/reference/expressions.rst Doc/reference/expressions.rst index 655ebde..48cc00d 100644 --- Doc/reference/expressions.rst +++ Doc/reference/expressions.rst @@ -318,25 +318,58 @@ Yield expressions .. productionlist:: yield_atom: "(" `yield_expression` ")" - yield_expression: "yield" [`expression_list`] + yield_expression: "yield" [`expression_list`] | "yield" "from" `expression` -The :keyword:`yield` expression is only used when defining a generator function, +The :keyword:`yield` statement is only used when defining a generator function, and can only be used in the body of a function definition. Using a -:keyword:`yield` expression in a function definition is sufficient to cause that +:keyword:`yield` statement in a function definition is sufficient to cause that definition to create a generator function instead of a normal function. When a generator function is called, it returns an iterator known as a generator. That generator then controls the execution of a generator function. -The execution starts when one of the generator's methods is called. At that -time, the execution proceeds to the first :keyword:`yield` expression, where it -is suspended again, returning the value of :token:`expression_list` to -generator's caller. By suspended we mean that all local state is retained, +The execution starts when one of the generator's methods is called. At that +time, the execution proceeds to the first :keyword:`yield` expression. What +happens next depends on whether the first, or the second more complicated form +of :token:`yield_expression` was used. + +In the first case, when ``from`` is not used, the execution of the generator +function is suspended again, returning the value of :token:`expression_list` to +generator's caller. By suspended we mean that all local state is retained, including the current bindings of local variables, the instruction pointer, and -the internal evaluation stack. When the execution is resumed by calling one of +the internal evaluation stack. When the execution is resumed by calling one of the generator's methods, the function can proceed exactly as if the -:keyword:`yield` expression was just another external call. The value of the -:keyword:`yield` expression after resuming depends on the method which resumed -the execution. +:keyword:`yield` expression was just another external call. + +The value of the :keyword:`yield` expression after resuming depends on the +method which resumed the execution. When the generator's +:meth:`~generator.__next__` method is used, the value of the yield expression is +:const:`None`, this is the most common case. When the generator's +:obj:`send(value) ` method is used, the ``value`` passed as an +argument becomes the value of the :token:`yield_expression`. + +In the second case, when ``from`` is present, :token:`expression` is expected to +yield an iterator, a "sub-generator". The evaluation of the ``yield`` statement +is then delegated to this sub-generator. By this we mean that the generator +function is suspended like in the first case, but calls to +:meth:`~generator.__next__`, :meth:`~generator.send`, :meth:`~generator.throw`, +and :meth:`~generator.close` are propagated to the sub-generator until it is +exhausted (and raises :exc:`StopIteration`) or until it terminates through an +exception (which is then re-raised at the point of the original ``yield +from``). This includes the call which causes the original generator function to +reach the ``yield from`` statement. If :token:`expression_list` yields something +that is not an iterator, :exc:`TypeError` is raised. The behaviour of a ``yield +from`` expression is similar to repeatedly calling ``return yield`` in a loop, +but in contrast also propagates the exceptions and values injected with +:meth:`~generator.throw` and :meth:`~generator.send`. + +The :attr:`~StopIteration.value` attribute of :exc:`StopIteration` used to +signal the exhaustion of the sub-generator becomes the value of the ``yield +from`` expression. It can be either set explicitely when raising +:exc:`StopIteration`, or automatically when the sub-generator is a generator, by +returning a value from the sub-generator function. + +The parentheses can be ommited when the :token:`yield_expression` +occurs in a top-level expression on the right-hand side of an assignment. .. index:: single: coroutine @@ -346,11 +379,13 @@ suspended. The only difference is that a generator function cannot control where should the execution continue after it yields; the control is always transferred to the generator's caller. -The :keyword:`yield` statement is allowed in the :keyword:`try` clause of a -:keyword:`try` ... :keyword:`finally` construct. If the generator is not -resumed before it is finalized (by reaching a zero reference count or by being -garbage collected), the generator-iterator's :meth:`close` method will be -called, allowing any pending :keyword:`finally` clauses to execute. +The :keyword:`yield` statement is allowed anywhere in the body of the generator +function, also in the :keyword:`try` clause of a :keyword:`try` ... +:keyword:`finally` construct. The :keyword:`finally` clause is still guaranteed +to be executed before the interpreter terminates. Before the generator is +destroyed (after reaching a zero reference count or being garbage collected), +the generator-iterator's :meth:`~generator.close` method is called, allowing any +pending :keyword:`finally` clauses to execute. .. index:: object: generator @@ -367,7 +402,7 @@ generator function: with a :meth:`__next__` method, the current :keyword:`yield` expression always evaluates to :const:`None`. The execution then continues to the next :keyword:`yield` expression, where the generator is suspended again, and the - value of the :token:`expression_list` is returned to :meth:`next`'s caller. + value of the :token:`expression_list` is returned to :meth:`__next__`'s caller. If the generator exits without yielding another value, a :exc:`StopIteration` exception is raised. @@ -402,7 +437,7 @@ generator function: Raises a :exc:`GeneratorExit` at the point where the generator function was paused. If the generator function then raises :exc:`StopIteration` (by exiting normally, or due to already being closed) or :exc:`GeneratorExit` (by - not catching the exception), close returns to its caller. If the generator + not catching the exception), :meth:`close` returns to its caller. If the generator yields a value, a :exc:`RuntimeError` is raised. If the generator raises any other exception, it is propagated to the caller. :meth:`close` does nothing if the generator has already exited due to an exception or normal exit. @@ -415,7 +450,7 @@ generator functions:: ... try: ... while True: ... try: - ... value = (yield value) + ... value = yield value ... except Exception as e: ... value = e ... finally: @@ -434,6 +469,27 @@ generator functions:: >>> generator.close() Don't forget to clean up when 'close()' is called. +When using :token:`yield_from`, work is delegated to the subgenerator:: + + >>> def outer(): + ... print("Outer generator started") + ... try: + ... yield from echo() + ... except GeneratorExit: + ... print("Outer generator done") + >>> generator = outer() + >>> next(generator) + Outer generator started + Execution starts when 'next()' is called for the first time. + >>> generator.send(2) + 2 + >>> generator.throw(TypeError, "spam") + TypeError('spam',) + >>> generator.close() + Don't forget to clean up when 'close()' is called. + Outer generator done + >>> generator.close() + .. seealso:: @@ -444,6 +500,10 @@ generator functions:: The proposal to enhance the API and syntax of generators, making them usable as simple coroutines. + :pep:`0380` - Syntax for Delegating to a Subgenerator + The proposal to introduce the :token:`yield_from` syntax, making + delegation to sub-generators easy. + .. _primaries: diff --git Doc/reference/simple_stmts.rst Doc/reference/simple_stmts.rst index a375117..ea62ec5 100644 --- Doc/reference/simple_stmts.rst +++ Doc/reference/simple_stmts.rst @@ -450,34 +450,10 @@ The :keyword:`yield` statement is only used when defining a generator function, and is only used in the body of the generator function. Using a :keyword:`yield` statement in a function definition is sufficient to cause that definition to create a generator function instead of a normal function. -When a generator function is called, it returns an iterator known as a generator -iterator, or more commonly, a generator. The body of the generator function is -executed by calling the :func:`next` function on the generator repeatedly until -it raises an exception. - -When a :keyword:`yield` statement is executed, the state of the generator is -frozen and the value of :token:`expression_list` is returned to :meth:`next`'s -caller. By "frozen" we mean that all local state is retained, including the -current bindings of local variables, the instruction pointer, and the internal -evaluation stack: enough information is saved so that the next time :func:`next` -is invoked, the function can proceed exactly as if the :keyword:`yield` -statement were just another external call. - -The :keyword:`yield` statement is allowed in the :keyword:`try` clause of a -:keyword:`try` ... :keyword:`finally` construct. If the generator is not -resumed before it is finalized (by reaching a zero reference count or by being -garbage collected), the generator-iterator's :meth:`close` method will be -called, allowing any pending :keyword:`finally` clauses to execute. .. seealso:: - :pep:`0255` - Simple Generators - The proposal for adding generators and the :keyword:`yield` statement to Python. - - :pep:`0342` - Coroutines via Enhanced Generators - The proposal that, among other generator enhancements, proposed allowing - :keyword:`yield` to appear inside a :keyword:`try` ... :keyword:`finally` block. - + The documentation for the `yield expression `_. .. _raise: diff --git Modules/_testembed Modules/_testembed index 7a96119..e7644ce 100755 Binary files Modules/_testembed and Modules/_testembed differ