Skip to content

Commit 0064516

Browse files
Fidget-SpinnerErlend Egeberg AaslandAlexWaygood
authored
[3.9] bpo-45680: Clarify documentation on GenericAlias objects (GH-29335) (GH-30689)
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 GH-29308, and previous BPO issue [42280](https://bugs.python.org/issue42280). Also improved references in glossary and typing docs. Fixed some links. (cherry picked from commit 0eae9a2) Co-Authored-By: Erlend Egeberg Aasland <[email protected]> Co-Authored-By: Ken Jin <[email protected]> Co-Authored-By: Alex Waygood <[email protected]>
1 parent 331378d commit 0064516

File tree

1 file changed

+84
-33
lines changed

1 file changed

+84
-33
lines changed

Doc/library/stdtypes.rst

Lines changed: 84 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4740,33 +4740,54 @@ Generic Alias Type
47404740
object: GenericAlias
47414741
pair: Generic; Alias
47424742

4743-
``GenericAlias`` objects are created by subscripting a class (usually a
4744-
container), such as ``list[int]``. They are intended primarily for
4743+
``GenericAlias`` objects are generally created by
4744+
:ref:`subscripting <subscriptions>` a class. They are most often used with
4745+
:ref:`container classes <sequence-types>`, such as :class:`list` or
4746+
:class:`dict`. For example, ``list[int]`` is a ``GenericAlias`` object created
4747+
by subscripting the ``list`` class with the argument :class:`int`.
4748+
``GenericAlias`` objects are intended primarily for use with
47454749
:term:`type annotations <annotation>`.
47464750

4747-
Usually, the :ref:`subscription <subscriptions>` of container objects calls the
4748-
method :meth:`__getitem__` of the object. However, the subscription of some
4749-
containers' classes may call the classmethod :meth:`__class_getitem__` of the
4750-
class instead. The classmethod :meth:`__class_getitem__` should return a
4751-
``GenericAlias`` object.
4752-
47534751
.. note::
4754-
If the :meth:`__getitem__` of the class' metaclass is present, it will take
4755-
precedence over the :meth:`__class_getitem__` defined in the class (see
4756-
:pep:`560` for more details).
47574752

4758-
The ``GenericAlias`` object acts as a proxy for :term:`generic types
4759-
<generic type>`, implementing *parameterized generics* - a specific instance
4760-
of a generic which provides the types for container elements.
4753+
It is generally only possible to subscript a class if the class implements
4754+
the special method :meth:`~object.__class_getitem__`.
4755+
4756+
A ``GenericAlias`` object acts as a proxy for a :term:`generic type`,
4757+
implementing *parameterized generics*.
4758+
4759+
For a container class, the
4760+
argument(s) supplied to a :ref:`subscription <subscriptions>` of the class may
4761+
indicate the type(s) of the elements an object contains. For example,
4762+
``set[bytes]`` can be used in type annotations to signify a :class:`set` in
4763+
which all the elements are of type :class:`bytes`.
4764+
4765+
For a class which defines :meth:`~object.__class_getitem__` but is not a
4766+
container, the argument(s) supplied to a subscription of the class will often
4767+
indicate the return type(s) of one or more methods defined on an object. For
4768+
example, :mod:`regular expressions <re>` can be used on both the :class:`str` data
4769+
type and the :class:`bytes` data type:
4770+
4771+
* If ``x = re.search('foo', 'foo')``, ``x`` will be a
4772+
:ref:`re.Match <match-objects>` object where the return values of
4773+
``x.group(0)`` and ``x[0]`` will both be of type :class:`str`. We can
4774+
represent this kind of object in type annotations with the ``GenericAlias``
4775+
``re.Match[str]``.
4776+
4777+
* If ``y = re.search(b'bar', b'bar')``, (note the ``b`` for :class:`bytes`),
4778+
``y`` will also be an instance of ``re.Match``, but the return
4779+
values of ``y.group(0)`` and ``y[0]`` will both be of type
4780+
:class:`bytes`. In type annotations, we would represent this
4781+
variety of :ref:`re.Match <match-objects>` objects with ``re.Match[bytes]``.
47614782

4762-
The user-exposed type for the ``GenericAlias`` object can be accessed from
4763-
:class:`types.GenericAlias` and used for :func:`isinstance` checks. It can
4764-
also be used to create ``GenericAlias`` objects directly.
4783+
``GenericAlias`` objects are instances of the class
4784+
:class:`types.GenericAlias`, which can also be used to create ``GenericAlias``
4785+
objects directly.
47654786

47664787
.. describe:: T[X, Y, ...]
47674788

4768-
Creates a ``GenericAlias`` representing a type ``T`` containing elements
4769-
of types *X*, *Y*, and more depending on the ``T`` used.
4789+
Creates a ``GenericAlias`` representing a type ``T`` parameterized by types
4790+
*X*, *Y*, and more depending on the ``T`` used.
47704791
For example, a function expecting a :class:`list` containing
47714792
:class:`float` elements::
47724793

@@ -4791,7 +4812,7 @@ The builtin functions :func:`isinstance` and :func:`issubclass` do not accept
47914812

47924813
The Python runtime does not enforce :term:`type annotations <annotation>`.
47934814
This extends to generic types and their type parameters. When creating
4794-
an object from a ``GenericAlias``, container elements are not checked
4815+
a container object from a ``GenericAlias``, the elements in the container are not checked
47954816
against their type. For example, the following code is discouraged, but will
47964817
run without errors::
47974818

@@ -4818,8 +4839,8 @@ Calling :func:`repr` or :func:`str` on a generic shows the parameterized type::
48184839
>>> str(list[int])
48194840
'list[int]'
48204841

4821-
The :meth:`__getitem__` method of generics will raise an exception to disallow
4822-
mistakes like ``dict[str][str]``::
4842+
The :meth:`~object.__getitem__` method of generic containers will raise an
4843+
exception to disallow mistakes like ``dict[str][str]``::
48234844

48244845
>>> dict[str][str]
48254846
Traceback (most recent call last):
@@ -4828,18 +4849,19 @@ mistakes like ``dict[str][str]``::
48284849

48294850
However, such expressions are valid when :ref:`type variables <generics>` are
48304851
used. The index must have as many elements as there are type variable items
4831-
in the ``GenericAlias`` object's :attr:`__args__ <genericalias.__args__>`. ::
4852+
in the ``GenericAlias`` object's :attr:`~genericalias.__args__`. ::
48324853

48334854
>>> from typing import TypeVar
48344855
>>> Y = TypeVar('Y')
48354856
>>> dict[str, Y][int]
48364857
dict[str, int]
48374858

48384859

4839-
Standard Generic Collections
4840-
----------------------------
4860+
Standard Generic Classes
4861+
------------------------
48414862

4842-
These standard library collections support parameterized generics.
4863+
The following standard library classes support parameterized generics. This
4864+
list is non-exhaustive.
48434865

48444866
* :class:`tuple`
48454867
* :class:`list`
@@ -4877,12 +4899,33 @@ These standard library collections support parameterized generics.
48774899
* :class:`collections.abc.ValuesView`
48784900
* :class:`contextlib.AbstractContextManager`
48794901
* :class:`contextlib.AbstractAsyncContextManager`
4902+
* :class:`dataclasses.Field`
4903+
* :class:`functools.cached_property`
4904+
* :class:`functools.partialmethod`
4905+
* :class:`os.PathLike`
4906+
* :class:`pathlib.Path`
4907+
* :class:`pathlib.PurePath`
4908+
* :class:`pathlib.PurePosixPath`
4909+
* :class:`pathlib.PureWindowsPath`
4910+
* :class:`queue.LifoQueue`
4911+
* :class:`queue.Queue`
4912+
* :class:`queue.PriorityQueue`
4913+
* :class:`queue.SimpleQueue`
48804914
* :ref:`re.Pattern <re-objects>`
48814915
* :ref:`re.Match <match-objects>`
4916+
* :class:`shelve.BsdDbShelf`
4917+
* :class:`shelve.DbfilenameShelf`
4918+
* :class:`shelve.Shelf`
4919+
* :class:`types.MappingProxyType`
4920+
* :class:`weakref.WeakKeyDictionary`
4921+
* :class:`weakref.WeakMethod`
4922+
* :class:`weakref.WeakSet`
4923+
* :class:`weakref.WeakValueDictionary`
48824924

48834925

4884-
Special Attributes of Generic Alias
4885-
-----------------------------------
4926+
4927+
Special Attributes of ``GenericAlias`` objects
4928+
----------------------------------------------
48864929

48874930
All parameterized generics implement special read-only attributes.
48884931

@@ -4897,8 +4940,8 @@ All parameterized generics implement special read-only attributes.
48974940
.. attribute:: genericalias.__args__
48984941

48994942
This attribute is a :class:`tuple` (possibly of length 1) of generic
4900-
types passed to the original :meth:`__class_getitem__`
4901-
of the generic container::
4943+
types passed to the original :meth:`~object.__class_getitem__` of the
4944+
generic class::
49024945

49034946
>>> dict[str, list[int]].__args__
49044947
(<class 'str'>, list[int])
@@ -4918,9 +4961,17 @@ All parameterized generics implement special read-only attributes.
49184961

49194962
.. seealso::
49204963

4921-
* :pep:`585` -- "Type Hinting Generics In Standard Collections"
4922-
* :meth:`__class_getitem__` -- Used to implement parameterized generics.
4923-
* :ref:`generics` -- Generics in the :mod:`typing` module.
4964+
:pep:`484` - Type Hints
4965+
Introducing Python's framework for type annotations.
4966+
4967+
:pep:`585` - Type Hinting Generics In Standard Collections
4968+
Introducing the ability to natively parameterize standard-library
4969+
classes, provided they implement the special class method
4970+
:meth:`~object.__class_getitem__`.
4971+
4972+
:ref:`Generics`, :ref:`user-defined generics <user-defined-generics>` and :class:`typing.Generic`
4973+
Documentation on how to implement generic classes that can be
4974+
parameterized at runtime and understood by static type-checkers.
49244975

49254976
.. versionadded:: 3.9
49264977

0 commit comments

Comments
 (0)