Skip to content
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

Small improvements to protocol documentation #15460

Merged
merged 1 commit into from Jun 18, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
50 changes: 24 additions & 26 deletions docs/source/protocols.rst
Expand Up @@ -3,26 +3,24 @@
Protocols and structural subtyping
==================================

Mypy supports two ways of deciding whether two classes are compatible
as types: nominal subtyping and structural subtyping.

*Nominal* subtyping is strictly based on the class hierarchy. If class ``D``
inherits class ``C``, it's also a subtype of ``C``, and instances of
``D`` can be used when ``C`` instances are expected. This form of
subtyping is used by default in mypy, since it's easy to understand
and produces clear and concise error messages, and since it matches
how the native :py:func:`isinstance <isinstance>` check works -- based on class
The Python type system supports two ways of deciding whether two objects are
compatible as types: nominal subtyping and structural subtyping.

*Nominal* subtyping is strictly based on the class hierarchy. If class ``Dog``
inherits class ``Animal``, it's a subtype of ``Animal``. Instances of ``Dog``
can be used when ``Animal`` instances are expected. This form of subtyping
subtyping is what Python's type system predominantly uses: it's easy to
understand and produces clear and concise error messages, and matches how the
native :py:func:`isinstance <isinstance>` check works -- based on class
hierarchy.

*Structural* subtyping is based on the operations that can be performed with an object. Class ``D`` is
a structural subtype of class ``C`` if the former has all attributes
and methods of the latter, and with compatible types.
*Structural* subtyping is based on the operations that can be performed with an
object. Class ``Dog`` is a structural subtype of class ``Animal`` if the former
has all attributes and methods of the latter, and with compatible types.

Structural subtyping can be seen as a static equivalent of duck
typing, which is well known to Python programmers. Mypy provides
support for structural subtyping via protocol classes described
below. See :pep:`544` for the detailed specification of protocols
and structural subtyping in Python.
Structural subtyping can be seen as a static equivalent of duck typing, which is
well known to Python programmers. See :pep:`544` for the detailed specification
of protocols and structural subtyping in Python.

.. _predefined_protocols:

Expand Down Expand Up @@ -60,8 +58,7 @@ For example, ``IntList`` below is iterable, over ``int`` values:

:ref:`predefined_protocols_reference` lists all protocols defined in
:py:mod:`typing` and the signatures of the corresponding methods you need to define
to implement each protocol (the signatures can be left out, as always, but mypy
won't type check unannotated methods).
to implement each protocol.

Simple user-defined protocols
*****************************
Expand Down Expand Up @@ -89,18 +86,12 @@ class:
for item in items:
item.close()

close_all([Resource(), open('some/file')]) # Okay!
close_all([Resource(), open('some/file')]) # OK

``Resource`` is a subtype of the ``SupportsClose`` protocol since it defines
a compatible ``close`` method. Regular file objects returned by :py:func:`open` are
similarly compatible with the protocol, as they support ``close()``.

.. note::

The ``Protocol`` base class is provided in the ``typing_extensions``
package for Python 3.4-3.7. Starting with Python 3.8, ``Protocol``
is included in the ``typing`` module.

Defining subprotocols and subclassing protocols
***********************************************

Expand Down Expand Up @@ -171,6 +162,13 @@ abstract:
ExplicitSubclass() # error: Cannot instantiate abstract class 'ExplicitSubclass'
# with abstract attributes 'attr' and 'method'

Similarly, explicitly assigning to a protocol instance can be a way to ask the
type checker to verify that your class implements a protocol:

.. code-block:: python

_proto: SomeProto = cast(ExplicitSubclass, None)

Invariance of protocol attributes
*********************************

Expand Down