Skip to content

Commit 0eae9a2

Browse files
AlexWaygoodErlend Egeberg AaslandFidget-Spinner
authored
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]>
1 parent 2792d6d commit 0eae9a2

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
@@ -4834,33 +4834,54 @@ Generic Alias Type
48344834
object: GenericAlias
48354835
pair: Generic; Alias
48364836

4837-
``GenericAlias`` objects are created by subscripting a class (usually a
4838-
container), such as ``list[int]``. They are intended primarily for
4837+
``GenericAlias`` objects are generally created by
4838+
:ref:`subscripting <subscriptions>` a class. They are most often used with
4839+
:ref:`container classes <sequence-types>`, such as :class:`list` or
4840+
:class:`dict`. For example, ``list[int]`` is a ``GenericAlias`` object created
4841+
by subscripting the ``list`` class with the argument :class:`int`.
4842+
``GenericAlias`` objects are intended primarily for use with
48394843
:term:`type annotations <annotation>`.
48404844

4841-
Usually, the :ref:`subscription <subscriptions>` of container objects calls the
4842-
method :meth:`__getitem__` of the object. However, the subscription of some
4843-
containers' classes may call the classmethod :meth:`__class_getitem__` of the
4844-
class instead. The classmethod :meth:`__class_getitem__` should return a
4845-
``GenericAlias`` object.
4846-
48474845
.. note::
4848-
If the :meth:`__getitem__` of the class' metaclass is present, it will take
4849-
precedence over the :meth:`__class_getitem__` defined in the class (see
4850-
:pep:`560` for more details).
48514846

4852-
The ``GenericAlias`` object acts as a proxy for :term:`generic types
4853-
<generic type>`, implementing *parameterized generics* - a specific instance
4854-
of a generic which provides the types for container elements.
4847+
It is generally only possible to subscript a class if the class implements
4848+
the special method :meth:`~object.__class_getitem__`.
4849+
4850+
A ``GenericAlias`` object acts as a proxy for a :term:`generic type`,
4851+
implementing *parameterized generics*.
4852+
4853+
For a container class, the
4854+
argument(s) supplied to a :ref:`subscription <subscriptions>` of the class may
4855+
indicate the type(s) of the elements an object contains. For example,
4856+
``set[bytes]`` can be used in type annotations to signify a :class:`set` in
4857+
which all the elements are of type :class:`bytes`.
4858+
4859+
For a class which defines :meth:`~object.__class_getitem__` but is not a
4860+
container, the argument(s) supplied to a subscription of the class will often
4861+
indicate the return type(s) of one or more methods defined on an object. For
4862+
example, :mod:`regular expressions <re>` can be used on both the :class:`str` data
4863+
type and the :class:`bytes` data type:
4864+
4865+
* If ``x = re.search('foo', 'foo')``, ``x`` will be a
4866+
:ref:`re.Match <match-objects>` object where the return values of
4867+
``x.group(0)`` and ``x[0]`` will both be of type :class:`str`. We can
4868+
represent this kind of object in type annotations with the ``GenericAlias``
4869+
``re.Match[str]``.
48554870

4856-
The user-exposed type for the ``GenericAlias`` object can be accessed from
4857-
:class:`types.GenericAlias` and used for :func:`isinstance` checks. It can
4858-
also be used to create ``GenericAlias`` objects directly.
4871+
* If ``y = re.search(b'bar', b'bar')``, (note the ``b`` for :class:`bytes`),
4872+
``y`` will also be an instance of ``re.Match``, but the return
4873+
values of ``y.group(0)`` and ``y[0]`` will both be of type
4874+
:class:`bytes`. In type annotations, we would represent this
4875+
variety of :ref:`re.Match <match-objects>` objects with ``re.Match[bytes]``.
4876+
4877+
``GenericAlias`` objects are instances of the class
4878+
:class:`types.GenericAlias`, which can also be used to create ``GenericAlias``
4879+
objects directly.
48594880

48604881
.. describe:: T[X, Y, ...]
48614882

4862-
Creates a ``GenericAlias`` representing a type ``T`` containing elements
4863-
of types *X*, *Y*, and more depending on the ``T`` used.
4883+
Creates a ``GenericAlias`` representing a type ``T`` parameterized by types
4884+
*X*, *Y*, and more depending on the ``T`` used.
48644885
For example, a function expecting a :class:`list` containing
48654886
:class:`float` elements::
48664887

@@ -4885,7 +4906,7 @@ The builtin functions :func:`isinstance` and :func:`issubclass` do not accept
48854906

48864907
The Python runtime does not enforce :term:`type annotations <annotation>`.
48874908
This extends to generic types and their type parameters. When creating
4888-
an object from a ``GenericAlias``, container elements are not checked
4909+
a container object from a ``GenericAlias``, the elements in the container are not checked
48894910
against their type. For example, the following code is discouraged, but will
48904911
run without errors::
48914912

@@ -4912,8 +4933,8 @@ Calling :func:`repr` or :func:`str` on a generic shows the parameterized type::
49124933
>>> str(list[int])
49134934
'list[int]'
49144935

4915-
The :meth:`__getitem__` method of generics will raise an exception to disallow
4916-
mistakes like ``dict[str][str]``::
4936+
The :meth:`~object.__getitem__` method of generic containers will raise an
4937+
exception to disallow mistakes like ``dict[str][str]``::
49174938

49184939
>>> dict[str][str]
49194940
Traceback (most recent call last):
@@ -4922,18 +4943,19 @@ mistakes like ``dict[str][str]``::
49224943

49234944
However, such expressions are valid when :ref:`type variables <generics>` are
49244945
used. The index must have as many elements as there are type variable items
4925-
in the ``GenericAlias`` object's :attr:`__args__ <genericalias.__args__>`. ::
4946+
in the ``GenericAlias`` object's :attr:`~genericalias.__args__`. ::
49264947

49274948
>>> from typing import TypeVar
49284949
>>> Y = TypeVar('Y')
49294950
>>> dict[str, Y][int]
49304951
dict[str, int]
49314952

49324953

4933-
Standard Generic Collections
4934-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4954+
Standard Generic Classes
4955+
^^^^^^^^^^^^^^^^^^^^^^^^
49354956

4936-
These standard library collections support parameterized generics.
4957+
The following standard library classes support parameterized generics. This
4958+
list is non-exhaustive.
49374959

49384960
* :class:`tuple`
49394961
* :class:`list`
@@ -4971,12 +4993,33 @@ These standard library collections support parameterized generics.
49714993
* :class:`collections.abc.ValuesView`
49724994
* :class:`contextlib.AbstractContextManager`
49734995
* :class:`contextlib.AbstractAsyncContextManager`
4996+
* :class:`dataclasses.Field`
4997+
* :class:`functools.cached_property`
4998+
* :class:`functools.partialmethod`
4999+
* :class:`os.PathLike`
5000+
* :class:`pathlib.Path`
5001+
* :class:`pathlib.PurePath`
5002+
* :class:`pathlib.PurePosixPath`
5003+
* :class:`pathlib.PureWindowsPath`
5004+
* :class:`queue.LifoQueue`
5005+
* :class:`queue.Queue`
5006+
* :class:`queue.PriorityQueue`
5007+
* :class:`queue.SimpleQueue`
49745008
* :ref:`re.Pattern <re-objects>`
49755009
* :ref:`re.Match <match-objects>`
5010+
* :class:`shelve.BsdDbShelf`
5011+
* :class:`shelve.DbfilenameShelf`
5012+
* :class:`shelve.Shelf`
5013+
* :class:`types.MappingProxyType`
5014+
* :class:`weakref.WeakKeyDictionary`
5015+
* :class:`weakref.WeakMethod`
5016+
* :class:`weakref.WeakSet`
5017+
* :class:`weakref.WeakValueDictionary`
5018+
49765019

49775020

4978-
Special Attributes of Generic Alias
4979-
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
5021+
Special Attributes of ``GenericAlias`` objects
5022+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
49805023

49815024
All parameterized generics implement special read-only attributes.
49825025

@@ -4991,8 +5034,8 @@ All parameterized generics implement special read-only attributes.
49915034
.. attribute:: genericalias.__args__
49925035

49935036
This attribute is a :class:`tuple` (possibly of length 1) of generic
4994-
types passed to the original :meth:`__class_getitem__`
4995-
of the generic container::
5037+
types passed to the original :meth:`~object.__class_getitem__` of the
5038+
generic class::
49965039

49975040
>>> dict[str, list[int]].__args__
49985041
(<class 'str'>, list[int])
@@ -5017,9 +5060,17 @@ All parameterized generics implement special read-only attributes.
50175060

50185061
.. seealso::
50195062

5020-
* :pep:`585` -- "Type Hinting Generics In Standard Collections"
5021-
* :meth:`__class_getitem__` -- Used to implement parameterized generics.
5022-
* :ref:`generics` -- Generics in the :mod:`typing` module.
5063+
:pep:`484` - Type Hints
5064+
Introducing Python's framework for type annotations.
5065+
5066+
:pep:`585` - "Type Hinting Generics In Standard Collections"
5067+
Introducing the ability to natively parameterize standard-library
5068+
classes, provided they implement the special class method
5069+
:meth:`~object.__class_getitem__`.
5070+
5071+
:ref:`Generics`, :ref:`user-defined generics <user-defined-generics>` and :class:`typing.Generic`
5072+
Documentation on how to implement generic classes that can be
5073+
parameterized at runtime and understood by static type-checkers.
50235074

50245075
.. versionadded:: 3.9
50255076

0 commit comments

Comments
 (0)