-
-
Notifications
You must be signed in to change notification settings - Fork 32.5k
bpo-37058: PEP 544: Add Protocol to typing module #13585
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 11 commits
442da2c
0764a0e
727314d
78d2ddd
a540902
0a9d22f
5fac4c3
815c9b2
d521860
5e77669
2de4ce7
c90f6f2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,7 +17,8 @@ | |
|
||
-------------- | ||
|
||
This module supports type hints as specified by :pep:`484` and :pep:`526`. | ||
This module supports 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 such approach is that a class had | ||
ilevkivskyi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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]: ... | ||
|
||
The :pep:`544` allows to solve this problem by allowing users to write | ||
ilevkivskyi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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,37 @@ 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 as:: | ||
ilevkivskyi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is okay for now, but at some point we may want to make it so that the docs are self-contained without any references to PEPs. (This is so that in the future the implementation can evolve, and the docs should describe the current implementation, while the PEP describes the implementation as it was at the time the PEP was finalized.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, we can expand the docs later. |
||
:func:`runtime_checkable` act as simple-minded runtime protocols that | ||
ilevkivskyi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
check only the presence of given attributes, ignoring their type signatures. | ||
Protocol classes can be generic, they are defined as:: | ||
ilevkivskyi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
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 +1107,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 protocol can be used with :func:`isinstance` and :func:`issubclass`. | ||
ilevkivskyi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Raise :exc:`TypeError` if applied to a non-protocol class. This allows | ||
ilevkivskyi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
a simple-minded structural check very similar to one trick ponies in | ||
ilevkivskyi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
: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. | ||
|
Uh oh!
There was an error while loading. Please reload this page.