-
-
Notifications
You must be signed in to change notification settings - Fork 35.3k
gh-141984: Move generator iterator reference out of syntax docs #154884
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
encukou
wants to merge
10
commits into
python:main
Choose a base branch
from
encukou:move-generator-iterator-out
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
415b5e0
Start moving generator reference out of syntax docs
encukou bf9219f
TMP
encukou 15b982e
reword agen.aclose()
encukou 9e5ce42
Merge in the main branch
encukou 80e390b
Fix a thinko
encukou 02b643f
Handle (re)moved IDs
encukou 832c7ce
Apply suggestions from code review
encukou 9c5b9be
Merge in the main branch
encukou 174f232
Make indentation more consistent
encukou 7b3ac38
Apply suggestions from code review
encukou File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -891,10 +891,12 @@ many numeric contexts, ``False`` and ``True`` behave like the integers 0 and 1, | |
| However, relying on this is discouraged; explicitly convert using :func:`int` | ||
| instead. | ||
|
|
||
| .. _iterator-types: | ||
|
|
||
| .. _typeiter: | ||
|
|
||
| Iterator Types | ||
| ============== | ||
| Iteration-related types | ||
| ======================= | ||
|
|
||
| .. index:: | ||
| single: iterator protocol | ||
|
|
@@ -907,6 +909,9 @@ using two distinct methods; these are used to allow user-defined classes to | |
| support iteration. Sequences, described below in more detail, always support | ||
| the iteration methods. | ||
|
|
||
| Iterables | ||
| --------- | ||
|
|
||
| One method needs to be defined for container objects to provide :term:`iterable` | ||
| support: | ||
|
|
||
|
|
@@ -923,10 +928,14 @@ support: | |
| :c:member:`~PyTypeObject.tp_iter` slot of the type structure for Python | ||
| objects in the Python/C API. | ||
|
|
||
| .. _stdtypes-iterators: | ||
|
|
||
| Iterators | ||
| --------- | ||
|
|
||
| The iterator objects themselves are required to support the following two | ||
| methods, which together form the :dfn:`iterator protocol`: | ||
|
|
||
|
|
||
| .. method:: iterator.__iter__() | ||
|
|
||
| Return the :term:`iterator` object itself. This is required to allow both | ||
|
|
@@ -955,16 +964,278 @@ Implementations that do not obey this property are deemed broken. | |
|
|
||
| .. _generator-types: | ||
|
|
||
| Generator Types | ||
| Generator types | ||
| --------------- | ||
|
|
||
| Python's :term:`generator`\s provide a convenient way to implement the iterator | ||
| protocol. If a container object's :meth:`~object.__iter__` method is implemented as a | ||
| generator, it will automatically return an iterator object (technically, a | ||
| generator object) supplying the :meth:`~iterator.__iter__` and :meth:`~generator.__next__` | ||
| methods. | ||
| More information about generators can be found in :ref:`the documentation for | ||
| the yield expression <yieldexpr>`. | ||
| Python's :term:`generators <generator>` -- or more precisely, | ||
| :term:`generator functions <generator function>` and | ||
| :term:`generator iterators <generator iterator>` -- provide a convenient way | ||
| to implement the iterator protocol. | ||
|
|
||
| A function that contains one or more :ref:`yield expressions <yieldexpr>` | ||
| is a :term:`generator function`. | ||
| For example:: | ||
|
|
||
| >>> def count_to_three(): | ||
| ... yield 0 | ||
| ... yield 1 | ||
| ... yield 2 | ||
| ... yield 3 | ||
|
|
||
| Generator functions behave as regular | ||
| :ref:`user-defined functions <user-defined-funcs>` | ||
| (for example, they have the same attributes), except that calling a generator | ||
| function returns a :ref:`generator iterator <generator-methods>`:: | ||
|
|
||
| >>> count_to_three() | ||
| <generator object count_to_three at 0x7f33a2305000> | ||
|
|
||
| Iterating a generator iterator executes code of the underlying | ||
| generator function, producing each :keyword:`yield`\ed value in turn:: | ||
|
|
||
| >>> for number in count_to_three(): | ||
| ... print(number) | ||
| 0 | ||
| 1 | ||
| 2 | ||
| 3 | ||
|
|
||
| >>> list(count_to_three()) | ||
| [0, 1, 2, 3] | ||
|
|
||
| One common use for generator functions is implementing the | ||
| :meth:`~object.__iter__` method of custom iterable objects. | ||
| For example:: | ||
|
|
||
| >>> class CardDeck: | ||
| ... def __iter__(self): | ||
| ... yield 'three of clubs' | ||
| ... yield 'ace of hearts' | ||
|
|
||
| >>> list(CardDeck()) | ||
| ['three of clubs', 'ace of hearts'] | ||
|
|
||
|
|
||
| .. index:: pair: object; generator | ||
| .. _generator-methods: | ||
|
|
||
| Generator iterators | ||
| ^^^^^^^^^^^^^^^^^^^ | ||
|
|
||
| Generator iterators implement the | ||
| :ref:`iterator protocol <stdtypes-iterators>`. | ||
| Iterating them drives execution of the underlying generator function. | ||
|
|
||
| .. index:: pair: exception; StopIteration | ||
|
|
||
| .. method:: generator.__next__() | ||
|
|
||
| Starts the execution of a generator function or resumes it at the | ||
| :ref:`yield expression <yieldexpr>` where the function is currently suspended. | ||
| When a generator function is resumed with a :meth:`~generator.__next__` | ||
| method, the current yield expression always evaluates to :const:`None`. | ||
| The execution then continues to the next yield expression, where the | ||
| generator is suspended again, and the value of the expression after the | ||
| :keyword:`yield` keyword is returned to :meth:`~generator.__next__`'s | ||
| caller. | ||
| If the generator exits without yielding another value, | ||
| :meth:`~generator.__next__` raises a :exc:`StopIteration` exception, | ||
| signalling that iteration has completed. | ||
|
|
||
| This method is normally called implicitly, for example by a :keyword:`for` | ||
| loop, or by the built-in :func:`next` function. | ||
|
|
||
| Generator iterators have a few more methods than generic iterators, which | ||
| can be used to control the execution of the underlying generator function: | ||
|
|
||
| .. method:: generator.send(value) | ||
|
|
||
| "Sends" a value into the generator function: the *value* argument becomes | ||
| the result of the current yield expression. | ||
|
|
||
| Otherwise, this method behaves like :meth:`~generator.__next__`: it resumes | ||
| the underlying function and either returns the next yielded value or raises | ||
| :exc:`StopIteration`. | ||
|
|
||
| When :meth:`send` is called to start the generator, it must be called | ||
| with :const:`None` as the argument, because there is no current yield | ||
| expression that could receive the value. | ||
|
|
||
|
|
||
| .. method:: generator.throw(value) | ||
| generator.throw(type[, value[, traceback]]) | ||
|
|
||
| Raises an exception at the point where the generator is currently suspended. | ||
|
|
||
| Otherwise, this method behaves like :meth:`~generator.__next__`: it resumes | ||
| the underlying function and either returns the next yielded value or raises | ||
| :exc:`StopIteration`. | ||
| If the generator function does not catch the passed-in exception, or | ||
| raises a different exception, then that exception propagates to the caller. | ||
|
|
||
| When :meth:`throw` is called to start the generator, the generator | ||
| immediately exits (that is, subsequent calls to :meth:`~generator.__next__` | ||
| will raise :exc:`StopIteration`) and the thrown exception is propagated to | ||
| :meth:`throw`'s caller. | ||
|
|
||
| In typical use, this is called with a single argument, an exception instance, | ||
| similar to the way the :keyword:`raise` keyword is used. | ||
|
|
||
| For backwards compatibility, however, the second signature is | ||
| supported, following a convention from older versions of Python. | ||
| The *type* argument should be an exception class, and *value* | ||
| should be an exception instance. If the *value* is not provided, the | ||
| *type* constructor is called to get an instance. If *traceback* | ||
| is provided, it is set on the exception, otherwise any existing | ||
| :attr:`~BaseException.__traceback__` attribute stored in *value* may | ||
| be cleared. | ||
|
|
||
| .. versionchanged:: 3.12 | ||
|
|
||
| The second signature \(type\[, value\[, traceback\]\]\) is deprecated and | ||
| may be removed in a future version of Python. | ||
|
|
||
| .. index:: pair: exception; GeneratorExit | ||
|
|
||
| .. method:: generator.close() | ||
|
|
||
| Raises a :exc:`GeneratorExit` exception at the point where the generator | ||
| function is currently suspended (equivalent to calling ``throw(GeneratorExit)``). | ||
|
|
||
| If the generator function has already exited (due to an exception or | ||
| normal return), or raises :exc:`GeneratorExit` (by not catching the | ||
| exception), :meth:`close` returns :const:`None`. | ||
| If the generator yields a value, a :exc:`RuntimeError` is raised. | ||
| If the generator raises any other exception, it is propagated to the caller. | ||
| If a generator returns a value upon being closed, that value is returned | ||
| by :meth:`close`. | ||
|
|
||
| When a generator iterator is garbage collected before it has exited, | ||
| :meth:`~generator.close` is called automatically. | ||
|
|
||
| .. versionchanged:: 3.13 | ||
|
|
||
| If a generator returns a value upon being closed, the value is returned | ||
| by :meth:`close`. | ||
| Previously, it returned ``None``. | ||
|
|
||
|
|
||
| Calling any of the generator methods (:meth:`~generator.__next__`, | ||
| :meth:`~generator.send`, :meth:`~generator.throw`, :meth:`~generator.close`) | ||
| while one of these methods is already executing | ||
| raises a :exc:`ValueError` exception. | ||
|
|
||
|
|
||
| .. index:: pair: object; asynchronous-generator | ||
| .. _asynchronous-generator-methods: | ||
|
|
||
| Asynchronous generator iterators | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
|
||
| This subsection describes the methods of an asynchronous generator iterator, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An expanded introduction would be nice here, too. Although that can be done in a follow up. |
||
| which are used to control the execution of an asynchronous generator function. | ||
|
|
||
|
|
||
| .. index:: pair: exception; StopAsyncIteration | ||
|
|
||
| .. method:: agen.__anext__() | ||
| :async: | ||
|
|
||
| Returns an :term:`awaitable` which when run starts to execute the | ||
| asynchronous generator function or resumes it at the | ||
| :ref:`yield expression <yieldexpr>` where the function is currently suspended. | ||
| When an asynchronous generator function is resumed with an | ||
| :meth:`~agen.__anext__` method, the current yield expression always | ||
| evaluates to :const:`None` in the returned awaitable, which when run will | ||
| continue to the next yield expression. | ||
| The value of the expression after the :keyword:`yield` keyword is the value | ||
| of the :exc:`StopIteration` exception raised by the completing coroutine. | ||
| If the asynchronous generator exits without yielding another value, the | ||
| awaitable instead raises a :exc:`StopAsyncIteration` exception, | ||
| signalling that the asynchronous iteration has completed. | ||
|
|
||
| This method is normally called implicitly by an :keyword:`async for` loop, | ||
| or by the built-in :func:`anext` function. | ||
|
|
||
|
|
||
| Asynchronous generator-iterators have a few more methods than generic | ||
| asynchronous iterators, which can be used to control the execution of | ||
| the underlying generator function: | ||
|
|
||
| .. method:: agen.asend(value) | ||
| :async: | ||
|
|
||
| Returns an awaitable which, when run, "sends" a value into the underlying | ||
| asynchronous generator function: the *value* argument becomes | ||
| the result of the current yield expression. | ||
|
|
||
| Otherwise, this method behaves like :meth:`~agen.__anext__`: when the | ||
| returned awaitable runs, it resumes the underlying function and either | ||
| returns the next yielded value as the value of the raised | ||
| :exc:`StopIteration`, or raises :exc:`StopAsyncIteration`. | ||
|
|
||
| When :meth:`asend` is called to start the asynchronous | ||
| generator, it must be called with :const:`None` as the argument, | ||
| because there is no yield expression that could receive the value. | ||
|
|
||
|
|
||
| .. method:: agen.athrow(value) | ||
| agen.athrow(type[, value[, traceback]]) | ||
| :async: | ||
|
|
||
| Returns an awaitable that, when run, raises an exception at the point where | ||
| the underlying asynchronous generator function is currently suspended. | ||
|
|
||
| Otherwise, this method behaves like :meth:`~agen.__anext__`: when the | ||
| returned awaitable runs, it resumes the underlying function (with an | ||
| exception raised) and either returns the next yielded value as the value of | ||
| the raised :exc:`StopIteration`, or raises :exc:`StopAsyncIteration`. | ||
| If the underlying function does not catch the passed-in exception, or | ||
| raises a different exception, then when the awaitable is run, that | ||
| exception propagates to the caller of the awaitable. | ||
|
|
||
| When :meth:`~agen.athrow` is called to start the generator, the generator | ||
| exits when the awaitable runs (that is, subsequent results from | ||
| :meth:`~agen.__anext__` will raise :exc:`StopAsyncIteration` when run) | ||
| and the thrown exception is propagated to the awaitable's caller. | ||
|
|
||
| In typical use, this is called with a single argument, an exception instance, | ||
| similar to the way the :keyword:`raise` keyword is used. | ||
|
|
||
| For backwards compatibility, however, the second signature is | ||
| supported. | ||
| An exception instance is created from three arguments in the same way as in | ||
| :meth:`generator.throw`. | ||
|
|
||
| .. versionchanged:: 3.12 | ||
|
|
||
| The second signature \(type\[, value\[, traceback\]\]\) is deprecated and | ||
| may be removed in a future version of Python. | ||
|
|
||
|
|
||
| .. index:: pair: exception; GeneratorExit | ||
|
|
||
| .. method:: agen.aclose() | ||
| :async: | ||
|
|
||
| Returns an awaitable that when run will throw a :exc:`GeneratorExit` into | ||
| the underlying asynchronous generator function at the point where it is | ||
| currently suspended (equivalent to calling ``athrow(GeneratorExit)``). | ||
|
|
||
| If the asynchronous generator function then exits gracefully, is already | ||
| closed, or raises :exc:`GeneratorExit` (by not catching the exception), | ||
| then the returned awaitable will raise a :exc:`StopIteration` exception. | ||
| Any further awaitables returned by subsequent calls to the asynchronous | ||
| generator will raise a :exc:`StopAsyncIteration` exception. | ||
|
|
||
| If the asynchronous generator yields a value, a :exc:`RuntimeError` is | ||
| raised by the awaitable. | ||
| If the asynchronous generator raises any other exception, that exception | ||
| is propagated to the caller of the awaitable. | ||
|
|
||
| If the asynchronous generator has already exited due to an exception or | ||
| normal exit, then further calls to :meth:`aclose` will return an awaitable | ||
| that does nothing. | ||
|
|
||
|
|
||
| .. _typesseq: | ||
|
|
||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This unfortunately isn't helping #126052.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but before that's solved, this is the place to put the info.