8000 [doc] bpo-45680: Disambiguate ``__getitem__`` and ``__class_getitem__`` in the data model. by AlexWaygood · Pull Request #29389 · python/cpython · GitHub
[go: up one dir, main page]

Skip to content

[doc] bpo-45680: Disambiguate __getitem__ and __class_getitem__ in the data model. #29389

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

Merged
merged 11 commits into from
Nov 18, 2021
79 changes: 71 additions & 8 deletions Doc/reference/datamodel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2215,23 +2215,80 @@ case the instance is itself a class.
Emulating generic types
-----------------------

One can implement the generic class syntax as specified by :pep:`484`
(for example ``List[int]``) by defining a special method:
When using :term:`type annotations<annotation>`, it is often useful to
*parameterize* a generic type using Python's square-brackets notation.
For example, the annotation ``list[int]`` might be used to signify a
:class:`list` in which all the elements are of type :class:`int`.

.. seealso::

:pep:`484` - Type Hints
Introducing Python's framework for type annotations

:ref:`Generic Alias Types<types-genericalias>`
Documentation for objects representing parameterized generic classes

:class:`typing.Generic`
Inherit from :class:`typing.Generic` to implement generic classes that
can be parameterized at runtime and understood by static type-checkers.

A class can generally only be parameterized if it defines the special
classmethod ``__class_getitem__()``.

.. classmethod:: object.__class_getitem__(cls, key)

Return an object representing the specialization of a generic class
by type arguments found in *key*.

This method is looked up on the class object itself, and when defined in
the class body, this method is implicitly a class method. Note, this
mechanism is primarily reserved for use with static type hints, other usage
is discouraged.
``__getitem__`` *versus* ``__class_getitem__``
8000
.. seealso::
Usually, the :ref:`subscription <subscriptions>` of an object in Python
using the square-brackets notation will call the :meth:`~object.__getitem__`
instance method defined on the object's class.

:pep:`560` - Core support for typing module and generic types
For example, if we have a list ``food`` as follows::

food = ['spam', 'eggs', 'bacon']

Calling ``food[0]`` will return the same value as calling::

type(food).__getitem__(food, 0)

However, if a class defines the classmethod ``__class_getitem__()``, then
the subscription of that class may call the class's implementation of
``__class_getitem__()`` rather than :meth:`~object.__getitem__`.
``__class_getitem__()`` should return a
:ref:`GenericAlias<types-genericalias>` object if it is properly defined.

For example, because the :class:`list` class defines
``__class_getitem__()``, calling ``list[str]`` is equivalent to calling::

list.__class_getitem__(str)

rather than::

type(list).__getitem__(list, str)

.. note::
If :meth:`~object.__getitem__` is defined by a class's :term:`metaclass`, it
will take precedence over a ``__class_getitem__()`` classmethod
defined by the class. See :pep:`560` for more details.

.. note::
``__class_getitem__()`` was introduced to implement runtime parameterization
of standard-library generic classes in order to more easily apply
:term:`type-hints<type hint>` to these classes.

To implement custom generic classes that can be parameterized at runtime and
understood by static type-checkers, users should either inherit from a
standard library class that already implements ``__class_getitem__()``, or
inherit from :class:`typing.Generic`, which has its own implementation of
``__class_getitem__()``.

Custom implementations of ``__class_getitem__()`` on classes defined outside
of the standard library may not be understood by third-party type-checkers
such as mypy. Using ``__class_getitem__()`` on any class for purposes other
than type-hinting is discouraged.

.. _callable-types:

Expand Down Expand Up @@ -2344,6 +2401,12 @@ through the object's keys; for sequences, it should iterate through the values.
:keyword:`for` loops expect that an :exc:`IndexError` will be raised for illegal
indexes to allow proper detection of the end of the sequence.

.. note::

When :ref:`subscripting<subscriptions>` a *class*, the special
classmethod :meth:`~object.__class_getitem__` may be called instead of
``__getitem__()``.


.. method:: object.__setitem__(self, key, value)

Expand Down
0