Skip to content

Commit a6fe738

Browse files
committed
bpo-45680: Clarify documentation on GenericAlias objects
The documentation on ``GenericAlias`` objects implies at multiple points that only container classes can define ``__class_getitem__``. This is misleading. This PR proposes a rewrite of the documentation to clarify that non-container classes can define ``__class_getitem__``, and to clarify what it means when a non-container class is parameterized. See also: initial discussion of issues with this piece of documentation in python#29308, and previous BPO issue [42280](https://bugs.python.org/issue42280).
1 parent aae18a1 commit a6fe738

2 files changed

Lines changed: 90 additions & 34 deletions

File tree

‎Doc/library/stdtypes.rst‎

Lines changed: 87 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4822,35 +4822,66 @@ Generic Alias Type
48224822
object: GenericAlias
48234823
pair: Generic; Alias
48244824

4825-
``GenericAlias`` objects are created by subscripting a class (usually a
4826-
container), such as ``list[int]``. They are intended primarily for
4827-
:term:`type annotations <annotation>`.
4828-
4829-
Usually, the :ref:`subscription <subscriptions>` of container objects calls the
4830-
method :meth:`__getitem__` of the object. However, the subscription of some
4831-
containers' classes may call the classmethod :meth:`__class_getitem__` of the
4832-
class instead. The classmethod :meth:`__class_getitem__` should return a
4833-
``GenericAlias`` object.
4825+
``GenericAlias`` objects are generally created by
4826+
:ref:`subscripting<subscriptions>` a class. They are most often used with
4827+
container classes (e.g. :class:`list` or :class:`dict`). They are intended
4828+
primarily for use with :term:`type annotations <annotation>`. For example,
4829+
``list[int]`` is a ``GenericAlias`` object created by subscripting the
4830+
:class:`list` class with the argument :class:`int`.
4831+
4832+
Usually, the :ref:`subscription <subscriptions>` of an object in Python will
4833+
call the :meth:`__getitem__<object.__getitem__>` instance method defined on the
4834+
object's class. For example, if we have a list
4835+
``food = ['spam', 'eggs', 'bacon']``, calling ``food[0]`` will return the same
4836+
value as calling ``type(food).__getitem__(food, 0)``. However, if a class
4837+
defines the classmethod :meth:`__class_getitem__<object.__class_getitem__>`,
4838+
then the subscription of that class may instead call the class's implementation
4839+
of ``__class_getitem__``. This should return a ``GenericAlias`` object if it is
4840+
properly defined. For example, because the :class:`list` class defines
4841+
``__class_getitem__``, calling ``list[str]`` is equivalent to calling
4842+
``list.__class_getitem__(str)``, rather than
4843+
``type(list).__getitem__(list, str)``.
48344844

48354845
.. note::
4836-
If the :meth:`__getitem__` of the class' metaclass is present, it will take
4837-
precedence over the :meth:`__class_getitem__` defined in the class (see
4838-
:pep:`560` for more details).
4839-
4840-
The ``GenericAlias`` object acts as a proxy for :term:`generic types
4841-
<generic type>`, implementing *parameterized generics* - a specific instance
4842-
of a generic which provides the types for container elements.
4843-
4844-
The user-exposed type for the ``GenericAlias`` object can be accessed from
4845-
:class:`types.GenericAlias` and used for :func:`isinstance` checks. It can
4846-
also be used to create ``GenericAlias`` objects directly.
4846+
If :meth:`__getitem__<object.__getitem__>` is defined by a class's
4847+
:term:`metaclass`, it will take precedence over a
4848+
:meth:`__class_getitem__<object.__class_getitem__>` classmethod defined by
4849+
the class. See :pep:`560` for more details.
4850+
4851+
A ``GenericAlias`` object acts as a proxy for a :term:`generic types`,
4852+
implementing *parameterized generics*.
4853+
4854+
For a container class which implements
4855+
:meth:`__class_getitem__<object.__class_getitem__>`, the argument(s) supplied
4856+
to a :ref:`subscription<subscriptions>` of the class may indicate the type(s)
4857+
of the elements an object contains. For example, ``list[int]`` can be used in
4858+
type annotations to signify a :class:`list` in which all the elements are of
4859+
type :class:`int`.
4860+
4861+
For a class which defines :meth:`__class_getitem__<object.__class_getitem__>`
4862+
but is not a container, the
4863+
argument(s) supplied to a subscription of the class will often indicate the
4864+
return type(s) of one or more methods defined on an object. For example,
4865+
:mod:`regular expressions<re>` can be used on the :class:`str` data type and
4866+
the :class:`bytes` data type. If ``x = re.search('foo', 'foo')``, ``x`` will be
4867+
a :ref:`re.Match <match-objects>` object where the return values of
4868+
``x.group(0)`` and ``x[0]`` will both be of type :class:`str`. We can represent
4869+
this kind of object in type annotations with the ``GenericAlias``
4870+
``re.Match[str]``. If ``y = re.search(b'bar', b'bar')``, however, ``y`` will
4871+
also be an instance of ``re.Match``, but the return values of ``y.group(0)``
4872+
and ``y[0]`` will both be of type :class:`bytes`. In type annotations, we would
4873+
represent this subtype of :ref:`re.Match <match-objects>` with
4874+
``re.Match[bytes]``.
4875+
4876+
``GenericAlias`` objects are instances of the class
4877+
:class:`types.GenericAlias`, which can also be used to create ``GenericAlias``
4878+
objects directly.
48474879

48484880
.. describe:: T[X, Y, ...]
48494881

4850-
Creates a ``GenericAlias`` representing a type ``T`` containing elements
4851-
of types *X*, *Y*, and more depending on the ``T`` used.
4852-
For example, a function expecting a :class:`list` containing
4853-
:class:`float` elements::
4882+
Creates a ``GenericAlias`` representing a type ``T`` parameterized by types
4883+
*X*, *Y*, and more depending on the ``T`` used. For example, a function
4884+
expecting a :class:`list` containing :class:`float` elements::
48544885

48554886
def average(values: list[float]) -> float:
48564887
return sum(values) / len(values)
@@ -4900,8 +4931,8 @@ Calling :func:`repr` or :func:`str` on a generic shows the parameterized type::
49004931
>>> str(list[int])
49014932
'list[int]'
49024933

4903-
The :meth:`__getitem__` method of generics will raise an exception to disallow
4904-
mistakes like ``dict[str][str]``::
4934+
The :meth:`__getitem__<object.__getitem__>` method of generics will raise an
4935+
exception to disallow mistakes like ``dict[str][str]``::
49054936

49064937
>>> dict[str][str]
49074938
Traceback (most recent call last):
@@ -4918,10 +4949,11 @@ in the ``GenericAlias`` object's :attr:`__args__ <genericalias.__args__>`. ::
49184949
dict[str, int]
49194950

49204951

4921-
Standard Generic Collections
4922-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4952+
Standard Generic Classes
4953+
^^^^^^^^^^^^^^^^^^^^^^^^
49234954

4924-
These standard library collections support parameterized generics.
4955+
The following standard library classes support parameterized generics. This
4956+
list is non-exhaustive.
49254957

49264958
* :class:`tuple`
49274959
* :class:`list`
@@ -4959,12 +4991,31 @@ These standard library collections support parameterized generics.
49594991
* :class:`collections.abc.ValuesView`
49604992
* :class:`contextlib.AbstractContextManager`
49614993
* :class:`contextlib.AbstractAsyncContextManager`
4994+
* :class:`dataclasses.Field`
4995+
* :class:`functools.cached_property`
4996+
* :class:`functools.partialmethod`
4997+
* :class:`os.PathLike`
4998+
* :class:`pathlib.Path`
4999+
* :class:`pathlib.PurePath`
5000+
* :class:`pathlib.PurePosixPath`
5001+
* :class:`pathlib.PureWindowsPath`
5002+
* :class:`queue.LifoQueue`
5003+
* :class:`queue.Queue`
5004+
* :class:`queue.PriorityQueue`
5005+
* :class:`queue.SimpleQueue`
49625006
* :ref:`re.Pattern <re-objects>`
49635007
* :ref:`re.Match <match-objects>`
5008+
* :class:`shelve.Shelf`
5009+
* :class:`types.MappingProxyType`
5010+
* :class:`weakref.WeakKeyDictionary`
5011+
* :class:`weakref.WeakMethod`
5012+
* :class:`weakref.WeakSet`
5013+
* :class:`weakref.WeakValueDictionary`
5014+
49645015

49655016

4966-
Special Attributes of Generic Alias
4967-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5017+
Special Attributes of ``GenericAlias`` objects
5018+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
49685019

49695020
All parameterized generics implement special read-only attributes.
49705021

@@ -4979,8 +5030,9 @@ All parameterized generics implement special read-only attributes.
49795030
.. attribute:: genericalias.__args__
49805031

49815032
This attribute is a :class:`tuple` (possibly of length 1) of generic
4982-
types passed to the original :meth:`__class_getitem__`
4983-
of the generic container::
5033+
types passed to the original
5034+
:meth:`__class_getitem__<object.__class_getitem__>` of the generic
5035+
container::
49845036

49855037
>>> dict[str, list[int]].__args__
49865038
(<class 'str'>, list[int])
@@ -5006,7 +5058,8 @@ All parameterized generics implement special read-only attributes.
50065058
.. seealso::
50075059

50085060
* :pep:`585` -- "Type Hinting Generics In Standard Collections"
5009-
* :meth:`__class_getitem__` -- Used to implement parameterized generics.
5061+
* :meth:`__class_getitem__<object.__class_getitem__>` -- Used to implement
5062+
parameterized generics.
50105063
* :ref:`generics` -- Generics in the :mod:`typing` module.
50115064

50125065
.. versionadded:: 3.9
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Amend the docs on ``GenericAlias`` objects to clarify that non-container
2+
classes can also implement ``__class_getitem__``. Patch contributed by Alex
3+
Waygood.

0 commit comments

Comments
 (0)