summaryrefslogtreecommitdiffstats
path: root/Doc
diff options
context:
space:
mode:
authorIvan Levkivskyi <levkivskyi@gmail.com>2019-05-28 07:40:15 (GMT)
committerGitHub <noreply@github.com>2019-05-28 07:40:15 (GMT)
commit74d7f76e2c953fbfdb7ce01b7319d91d471cc5ef (patch)
tree6bba7b64dc4b4a88569809f0758113c87bb690b4 /Doc
parent3880f263d2994fb1eba25835dddccb0cf696fdf0 (diff)
downloadcpython-74d7f76e2c953fbfdb7ce01b7319d91d471cc5ef.zip
cpython-74d7f76e2c953fbfdb7ce01b7319d91d471cc5ef.tar.gz
cpython-74d7f76e2c953fbfdb7ce01b7319d91d471cc5ef.tar.bz2
bpo-37058: PEP 544: Add Protocol to typing module (GH-13585)
I tried to get rid of the `_ProtocolMeta`, but unfortunately it didn'y work. My idea to return a generic alias from `@runtime_checkable` made runtime protocols unpickleable. I am not sure what is worse (a custom metaclass or having some classes unpickleable), so I decided to stick with the status quo (since there were no complains so far). So essentially this is a copy of the implementation in `typing_extensions` with two modifications: * Rename `@runtime` to `@runtime_checkable` (plus corresponding updates). * Allow protocols that extend `collections.abc.Iterable` etc.
Diffstat (limited to 'Doc')
-rw-r--r--Doc/library/typing.rst98
1 files changed, 97 insertions, 1 deletions
diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst
index 27787fc..709580a 100644
--- a/Doc/library/typing.rst
+++ b/Doc/library/typing.rst
@@ -17,7 +17,8 @@
--------------
-This module supports type hints as specified by :pep:`484` and :pep:`526`.
+This module provides runtime support for type hints as specified by
+:pep:`484`, :pep:`526`, :pep:`544`, :pep:`586`, :pep:`589`, and :pep:`591`.
The most fundamental support consists of the types :data:`Any`, :data:`Union`,
:data:`Tuple`, :data:`Callable`, :class:`TypeVar`, and
:class:`Generic`. For full specification please see :pep:`484`. For
@@ -392,6 +393,48 @@ it as a return value) of a more specialized type is a type error. For example::
Use :class:`object` to indicate that a value could be any type in a typesafe
manner. Use :data:`Any` to indicate that a value is dynamically typed.
+
+Nominal vs structural subtyping
+-------------------------------
+
+Initially :pep:`484` defined Python static type system as using
+*nominal subtyping*. This means that a class ``A`` is allowed where
+a class ``B`` is expected if and only if ``A`` is a subclass of ``B``.
+
+This requirement previously also applied to abstract base classes, such as
+:class:`Iterable`. The problem with this approach is that a class had
+to be explicitly marked to support them, which is unpythonic and unlike
+what one would normally do in idiomatic dynamically typed Python code.
+For example, this conforms to the :pep:`484`::
+
+ from typing import Sized, Iterable, Iterator
+
+ class Bucket(Sized, Iterable[int]):
+ ...
+ def __len__(self) -> int: ...
+ def __iter__(self) -> Iterator[int]: ...
+
+:pep:`544` allows to solve this problem by allowing users to write
+the above code without explicit base classes in the class definition,
+allowing ``Bucket`` to be implicitly considered a subtype of both ``Sized``
+and ``Iterable[int]`` by static type checkers. This is known as
+*structural subtyping* (or static duck-typing)::
+
+ from typing import Iterator, Iterable
+
+ class Bucket: # Note: no base classes
+ ...
+ def __len__(self) -> int: ...
+ def __iter__(self) -> Iterator[int]: ...
+
+ def collect(items: Iterable[int]) -> int: ...
+ result = collect(Bucket()) # Passes type check
+
+Moreover, by subclassing a special class :class:`Protocol`, a user
+can define new custom protocols to fully enjoy structural subtyping
+(see examples below).
+
+
Classes, functions, and decorators
----------------------------------
@@ -459,6 +502,39 @@ The module defines the following classes, functions and decorators:
except KeyError:
return default
+.. 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 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
+
.. class:: Type(Generic[CT_co])
A variable annotated with ``C`` may accept a value of type ``C``. In
@@ -1033,6 +1109,26 @@ The module defines the following classes, functions and decorators:
Note that returning instances of private classes is not recommended.
It is usually preferable to make such classes public.
+.. 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:`Iterable`. For example::
+
+ @runtime_checkable
+ class Closable(Protocol):
+ def close(self): ...
+
+ assert isinstance(open('/some/file'), Closable)
+
+ **Warning:** this will check only the presence of the required methods,
+ not their type signatures!
+
+ .. versionadded:: 3.8
+
.. data:: Any
Special type indicating an unconstrained type.