Skip to content

Commit

Permalink
[3.11] typing docs: Move some classes out of the "Generics" section (G…
Browse files Browse the repository at this point in the history
…H-104707) (#104721)

- AnyStr can be used in type annotations, contrary to the section header
- Unpack can also be used in annotations, and its use is not restricted
  to generics. It makes more sense with other building blocks like Required.
- Protocol is not necessarily generic.

Also fix the indentation for two notes associated with Concatenate.

(cherry picked from commit ab71acd)

---------

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
  • Loading branch information
JelleZijlstra and AlexWaygood authored May 21, 2023
1 parent dc0c41b commit abb32de
Showing 1 changed file with 125 additions and 122 deletions.
247 changes: 125 additions & 122 deletions Doc/library/typing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,21 @@ These can be used as types in annotations and do not support ``[]``.
avoiding type checker errors with classes that can duck type anywhere or
are highly dynamic.

.. data:: AnyStr

``AnyStr`` is a :ref:`constrained type variable <typing-constrained-typevar>` defined as
``AnyStr = TypeVar('AnyStr', str, bytes)``.

It is meant to be used for functions that may accept any kind of string
without allowing different kinds of strings to mix. For example::

def concat(a: AnyStr, b: AnyStr) -> AnyStr:
return a + b

concat(u"foo", u"bar") # Ok, output has type 'unicode'
concat(b"foo", b"bar") # Ok, output has type 'bytes'
concat(u"foo", b"bar") # Error, cannot mix unicode and bytes

.. data:: LiteralString

Special type that includes only literal strings. A string
Expand Down Expand Up @@ -912,13 +927,13 @@ These can be used as types in annotations using ``[]``, each having a unique syn
# We don't need to pass in the lock ourselves thanks to the decorator.
sum_threadsafe([1.1, 2.2, 3.3])

.. versionadded:: 3.10
.. versionadded:: 3.10

.. seealso::
.. seealso::

* :pep:`612` -- Parameter Specification Variables (the PEP which introduced
``ParamSpec`` and ``Concatenate``).
* :class:`ParamSpec` and :class:`Callable`.
* :pep:`612` -- Parameter Specification Variables (the PEP which introduced
``ParamSpec`` and ``Concatenate``).
* :class:`ParamSpec` and :class:`Callable`.


.. class:: Type(Generic[CT_co])
Expand Down Expand Up @@ -1203,6 +1218,34 @@ These can be used as types in annotations using ``[]``, each having a unique syn
.. versionadded:: 3.10


.. data:: Unpack

A typing operator that conceptually marks an object as having been
unpacked. For example, using the unpack operator ``*`` on a
:class:`type variable tuple <TypeVarTuple>` is equivalent to using ``Unpack``
to mark the type variable tuple as having been unpacked::

Ts = TypeVarTuple('Ts')
tup: tuple[*Ts]
# Effectively does:
tup: tuple[Unpack[Ts]]

In fact, ``Unpack`` can be used interchangeably with ``*`` in the context
of :class:`typing.TypeVarTuple <TypeVarTuple>` and
:class:`builtins.tuple <tuple>` types. You might see ``Unpack`` being used
explicitly in older versions of Python, where ``*`` couldn't be used in
certain places::

# In older versions of Python, TypeVarTuple and Unpack
# are located in the `typing_extensions` backports package.
from typing_extensions import TypeVarTuple, Unpack

Ts = TypeVarTuple('Ts')
tup: tuple[*Ts] # Syntax error on Python <= 3.10!
tup: tuple[Unpack[Ts]] # Semantically equivalent, and backwards-compatible

.. versionadded:: 3.11

Building generic types
""""""""""""""""""""""

Expand Down Expand Up @@ -1404,32 +1447,6 @@ These are not used in annotations. They are building blocks for creating generic

.. versionadded:: 3.11

.. data:: Unpack

A typing operator that conceptually marks an object as having been
unpacked. For example, using the unpack operator ``*`` on a
:class:`type variable tuple <TypeVarTuple>` is equivalent to using ``Unpack``
to mark the type variable tuple as having been unpacked::

Ts = TypeVarTuple('Ts')
tup: tuple[*Ts]
# Effectively does:
tup: tuple[Unpack[Ts]]

In fact, ``Unpack`` can be used interchangeably with ``*`` in the context
of types. You might see ``Unpack`` being used explicitly in older versions
of Python, where ``*`` couldn't be used in certain places::

# In older versions of Python, TypeVarTuple and Unpack
# are located in the `typing_extensions` backports package.
from typing_extensions import TypeVarTuple, Unpack

Ts = TypeVarTuple('Ts')
tup: tuple[*Ts] # Syntax error on Python <= 3.10!
tup: tuple[Unpack[Ts]] # Semantically equivalent, and backwards-compatible

.. versionadded:: 3.11

.. class:: ParamSpec(name, *, bound=None, covariant=False, contravariant=False)

Parameter specification variable. A specialized version of
Expand Down Expand Up @@ -1528,97 +1545,6 @@ These are not used in annotations. They are building blocks for creating generic
.. versionadded:: 3.10


.. data:: AnyStr

``AnyStr`` is a :ref:`constrained type variable <typing-constrained-typevar>` defined as
``AnyStr = TypeVar('AnyStr', str, bytes)``.

It is meant to be used for functions that may accept any kind of string
without allowing different kinds of strings to mix. For example::

def concat(a: AnyStr, b: AnyStr) -> AnyStr:
return a + b

concat(u"foo", u"bar") # Ok, output has type 'unicode'
concat(b"foo", b"bar") # Ok, output has type 'bytes'
concat(u"foo", b"bar") # Error, cannot mix unicode and bytes

.. class:: Protocol(Generic)

Base class for protocol classes. Protocol classes are defined like this::

class Proto(Protocol):
def meth(self) -> int:
...

Such classes are primarily used with static type checkers that recognize
structural subtyping (static duck-typing), for example::

class C:
def meth(self) -> int:
return 0

def func(x: Proto) -> int:
return x.meth()

func(C()) # Passes static type check

See :pep:`544` for more details. Protocol classes decorated with
:func:`runtime_checkable` (described later) act as simple-minded runtime
protocols that check only the presence of given attributes, ignoring their
type signatures.

Protocol classes can be generic, for example::

class GenProto(Protocol[T]):
def meth(self) -> T:
...

.. versionadded:: 3.8

.. decorator:: runtime_checkable

Mark a protocol class as a runtime protocol.

Such a protocol can be used with :func:`isinstance` and :func:`issubclass`.
This raises :exc:`TypeError` when applied to a non-protocol class. This
allows a simple-minded structural check, very similar to "one trick ponies"
in :mod:`collections.abc` such as :class:`~collections.abc.Iterable`. For example::

@runtime_checkable
class Closable(Protocol):
def close(self): ...

assert isinstance(open('/some/file'), Closable)

@runtime_checkable
class Named(Protocol):
name: str

import threading
assert isinstance(threading.Thread(name='Bob'), Named)

.. note::

:func:`!runtime_checkable` will check only the presence of the required
methods or attributes, not their type signatures or types.
For example, :class:`ssl.SSLObject`
is a class, therefore it passes an :func:`issubclass`
check against :data:`Callable`. However, the
``ssl.SSLObject.__init__`` method exists only to raise a
:exc:`TypeError` with a more informative message, therefore making
it impossible to call (instantiate) :class:`ssl.SSLObject`.

.. note::

An :func:`isinstance` check against a runtime-checkable protocol can be
surprisingly slow compared to an ``isinstance()`` check against
a non-protocol class. Consider using alternative idioms such as
:func:`hasattr` calls for structural checks in performance-sensitive
code.

.. versionadded:: 3.8

Other special directives
""""""""""""""""""""""""

Expand Down Expand Up @@ -1707,6 +1633,83 @@ These are not used in annotations. They are building blocks for declaring types.
.. versionchanged:: 3.10
``NewType`` is now a class rather than a function.

.. class:: Protocol(Generic)

Base class for protocol classes. Protocol classes are defined like this::

class Proto(Protocol):
def meth(self) -> int:
...

Such classes are primarily used with static type checkers that recognize
structural subtyping (static duck-typing), for example::

class C:
def meth(self) -> int:
return 0

def func(x: Proto) -> int:
return x.meth()

func(C()) # Passes static type check

See :pep:`544` for more details. Protocol classes decorated with
:func:`runtime_checkable` (described later) act as simple-minded runtime
protocols that check only the presence of given attributes, ignoring their
type signatures.

Protocol classes can be generic, for example::

class GenProto(Protocol[T]):
def meth(self) -> T:
...

.. versionadded:: 3.8

.. decorator:: runtime_checkable

Mark a protocol class as a runtime protocol.

Such a protocol can be used with :func:`isinstance` and :func:`issubclass`.
This raises :exc:`TypeError` when applied to a non-protocol class. This
allows a simple-minded structural check, very similar to "one trick ponies"
in :mod:`collections.abc` such as :class:`~collections.abc.Iterable`. For example::

@runtime_checkable
class Closable(Protocol):
def close(self): ...

assert isinstance(open('/some/file'), Closable)

@runtime_checkable
class Named(Protocol):
name: str

import threading
assert isinstance(threading.Thread(name='Bob'), Named)

.. note::

:func:`!runtime_checkable` will check only the presence of the required
methods or attributes, not their type signatures or types.
For example, :class:`ssl.SSLObject`
is a class, therefore it passes an :func:`issubclass`
check against :data:`Callable`. However, the
``ssl.SSLObject.__init__`` method exists only to raise a
:exc:`TypeError` with a more informative message, therefore making
it impossible to call (instantiate) :class:`ssl.SSLObject`.

.. note::

An :func:`isinstance` check against a runtime-checkable protocol can be
surprisingly slow compared to an ``isinstance()`` check against
a non-protocol class. Consider using alternative idioms such as
:func:`hasattr` calls for structural checks in performance-sensitive
code.

.. versionadded:: 3.8


.. class:: TypedDict(dict)

Special construct to add type hints to a dictionary.
Expand Down

0 comments on commit abb32de

Please sign in to comment.