Skip to content

Commit f238ae6

Browse files
AlexWaygoodmiss-islington
authored andcommitted
bpo-45680: Clarify documentation on GenericAlias objects (pythonGH-29335)
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 pythonGH-29308, and previous BPO issue [42280](https://bugs.python.org/issue42280). Also improved references in glossary and typing docs. Fixed some links. Co-authored-by: Erlend Egeberg Aasland <[email protected]> Co-authored-by: Ken Jin <[email protected]> (cherry picked from commit 0eae9a2) Co-authored-by: Alex Waygood <[email protected]>
1 parent 0861a50 commit f238ae6

File tree

1 file changed

+84
-33
lines changed

1 file changed

+84
-33
lines changed

Doc/library/stdtypes.rst

+84-33
Original file line numberDiff line numberDiff line change
@@ -4796,33 +4796,54 @@ Generic Alias Type
47964796
object: GenericAlias
47974797
pair: Generic; Alias
47984798

4799-
``GenericAlias`` objects are created by subscripting a class (usually a
4800-
container), such as ``list[int]``. They are intended primarily for
4799+
``GenericAlias`` objects are generally created by
4800+
:ref:`subscripting <subscriptions>` a class. They are most often used with
4801+
:ref:`container classes <sequence-types>`, such as :class:`list` or
4802+
:class:`dict`. For example, ``list[int]`` is a ``GenericAlias`` object created
4803+
by subscripting the ``list`` class with the argument :class:`int`.
4804+
``GenericAlias`` objects are intended primarily for use with
48014805
:term:`type annotations <annotation>`.
48024806

4803-
Usually, the :ref:`subscription <subscriptions>` of container objects calls the
4804-
method :meth:`__getitem__` of the object. However, the subscription of some
4805-
containers' classes may call the classmethod :meth:`__class_getitem__` of the
4806-
class instead. The classmethod :meth:`__class_getitem__` should return a
4807-
``GenericAlias`` object.
4808-
48094807
.. note::
4810-
If the :meth:`__getitem__` of the class' metaclass is present, it will take
4811-
precedence over the :meth:`__class_getitem__` defined in the class (see
4812-
:pep:`560` for more details).
48134808

4814-
The ``GenericAlias`` object acts as a proxy for :term:`generic types
4815-
<generic type>`, implementing *parameterized generics* - a specific instance
4816-
of a generic which provides the types for container elements.
4809+
It is generally only possible to subscript a class if the class implements
4810+
the special method :meth:`~object.__class_getitem__`.
4811+
4812+
A ``GenericAlias`` object acts as a proxy for a :term:`generic type`,
4813+
implementing *parameterized generics*.
4814+
4815+
For a container class, the
4816+
argument(s) supplied to a :ref:`subscription <subscriptions>` of the class may
4817+
indicate the type(s) of the elements an object contains. For example,
4818+
``set[bytes]`` can be used in type annotations to signify a :class:`set` in
4819+
which all the elements are of type :class:`bytes`.
4820+
4821+
For a class which defines :meth:`~object.__class_getitem__` but is not a
4822+
container, the argument(s) supplied to a subscription of the class will often
4823+
indicate the return type(s) of one or more methods defined on an object. For
4824+
example, :mod:`regular expressions <re>` can be used on both the :class:`str` data
4825+
type and the :class:`bytes` data type:
4826+
4827+
* If ``x = re.search('foo', 'foo')``, ``x`` will be a
4828+
:ref:`re.Match <match-objects>` object where the return values of
4829+
``x.group(0)`` and ``x[0]`` will both be of type :class:`str`. We can
4830+
represent this kind of object in type annotations with the ``GenericAlias``
4831+
``re.Match[str]``.
48174832

4818-
The user-exposed type for the ``GenericAlias`` object can be accessed from
4819-
:class:`types.GenericAlias` and used for :func:`isinstance` checks. It can
4820-
also be used to create ``GenericAlias`` objects directly.
4833+
* If ``y = re.search(b'bar', b'bar')``, (note the ``b`` for :class:`bytes`),
4834+
``y`` will also be an instance of ``re.Match``, but the return
4835+
values of ``y.group(0)`` and ``y[0]`` will both be of type
4836+
:class:`bytes`. In type annotations, we would represent this
4837+
variety of :ref:`re.Match <match-objects>` objects with ``re.Match[bytes]``.
4838+
4839+
``GenericAlias`` objects are instances of the class
4840+
:class:`types.GenericAlias`, which can also be used to create ``GenericAlias``
4841+
objects directly.
48214842

48224843
.. describe:: T[X, Y, ...]
48234844

4824-
Creates a ``GenericAlias`` representing a type ``T`` containing elements
4825-
of types *X*, *Y*, and more depending on the ``T`` used.
4845+
Creates a ``GenericAlias`` representing a type ``T`` parameterized by types
4846+
*X*, *Y*, and more depending on the ``T`` used.
48264847
For example, a function expecting a :class:`list` containing
48274848
:class:`float` elements::
48284849

@@ -4847,7 +4868,7 @@ The builtin functions :func:`isinstance` and :func:`issubclass` do not accept
48474868

48484869
The Python runtime does not enforce :term:`type annotations <annotation>`.
48494870
This extends to generic types and their type parameters. When creating
4850-
an object from a ``GenericAlias``, container elements are not checked
4871+
a container object from a ``GenericAlias``, the elements in the container are not checked
48514872
against their type. For example, the following code is discouraged, but will
48524873
run without errors::
48534874

@@ -4874,8 +4895,8 @@ Calling :func:`repr` or :func:`str` on a generic shows the parameterized type::
48744895
>>> str(list[int])
48754896
'list[int]'
48764897

4877-
The :meth:`__getitem__` method of generics will raise an exception to disallow
4878-
mistakes like ``dict[str][str]``::
4898+
The :meth:`~object.__getitem__` method of generic containers will raise an
4899+
exception to disallow mistakes like ``dict[str][str]``::
48794900

48804901
>>> dict[str][str]
48814902
Traceback (most recent call last):
@@ -4884,18 +4905,19 @@ mistakes like ``dict[str][str]``::
48844905

48854906
However, such expressions are valid when :ref:`type variables <generics>` are
48864907
used. The index must have as many elements as there are type variable items
4887-
in the ``GenericAlias`` object's :attr:`__args__ <genericalias.__args__>`. ::
4908+
in the ``GenericAlias`` object's :attr:`~genericalias.__args__`. ::
48884909

48894910
>>> from typing import TypeVar
48904911
>>> Y = TypeVar('Y')
48914912
>>> dict[str, Y][int]
48924913
dict[str, int]
48934914

48944915

4895-
Standard Generic Collections
4896-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4916+
Standard Generic Classes
4917+
^^^^^^^^^^^^^^^^^^^^^^^^
48974918

4898-
These standard library collections support parameterized generics.
4919+
The following standard library classes support parameterized generics. This
4920+
list is non-exhaustive.
48994921

49004922
* :class:`tuple`
49014923
* :class:`list`
@@ -4933,12 +4955,33 @@ These standard library collections support parameterized generics.
49334955
* :class:`collections.abc.ValuesView`
49344956
* :class:`contextlib.AbstractContextManager`
49354957
* :class:`contextlib.AbstractAsyncContextManager`
4958+
* :class:`dataclasses.Field`
4959+
* :class:`functools.cached_property`
4960+
* :class:`functools.partialmethod`
4961+
* :class:`os.PathLike`
4962+
* :class:`pathlib.Path`
4963+
* :class:`pathlib.PurePath`
4964+
* :class:`pathlib.PurePosixPath`
4965+
* :class:`pathlib.PureWindowsPath`
4966+
* :class:`queue.LifoQueue`
4967+
* :class:`queue.Queue`
4968+
* :class:`queue.PriorityQueue`
4969+
* :class:`queue.SimpleQueue`
49364970
* :ref:`re.Pattern <re-objects>`
49374971
* :ref:`re.Match <match-objects>`
4972+
* :class:`shelve.BsdDbShelf`
4973+
* :class:`shelve.DbfilenameShelf`
4974+
* :class:`shelve.Shelf`
4975+
* :class:`types.MappingProxyType`
4976+
* :class:`weakref.WeakKeyDictionary`
4977+
* :class:`weakref.WeakMethod`
4978+
* :class:`weakref.WeakSet`
4979+
* :class:`weakref.WeakValueDictionary`
4980+
49384981

49394982

4940-
Special Attributes of Generic Alias
4941-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4983+
Special Attributes of ``GenericAlias`` objects
4984+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
49424985

49434986
All parameterized generics implement special read-only attributes.
49444987

@@ -4953,8 +4996,8 @@ All parameterized generics implement special read-only attributes.
49534996
.. attribute:: genericalias.__args__
49544997

49554998
This attribute is a :class:`tuple` (possibly of length 1) of generic
4956-
types passed to the original :meth:`__class_getitem__`
4957-
of the generic container::
4999+
types passed to the original :meth:`~object.__class_getitem__` of the
5000+
generic class::
49585001

49595002
>>> dict[str, list[int]].__args__
49605003
(<class 'str'>, list[int])
@@ -4979,9 +5022,17 @@ All parameterized generics implement special read-only attributes.
49795022

49805023
.. seealso::
49815024

4982-
* :pep:`585` -- "Type Hinting Generics In Standard Collections"
4983-
* :meth:`__class_getitem__` -- Used to implement parameterized generics.
4984-
* :ref:`generics` -- Generics in the :mod:`typing` module.
5025+
:pep:`484` - Type Hints
5026+
Introducing Python's framework for type annotations.
5027+
5028+
:pep:`585` - "Type Hinting Generics In Standard Collections"
5029+
Introducing the ability to natively parameterize standard-library
5030+
classes, provided they implement the special class method
5031+
:meth:`~object.__class_getitem__`.
5032+
5033+
:ref:`Generics`, :ref:`user-defined generics <user-defined-generics>` and :class:`typing.Generic`
5034+
Documentation on how to implement generic classes that can be
5035+
parameterized at runtime and understood by static type-checkers.
49855036

49865037
.. versionadded:: 3.9
49875038

0 commit comments

Comments
 (0)