Skip to content

Commit a7aab8f

Browse files
committed
Update docs to reflect the fact that Iterable etc. are protocols (#4344)
Also update the discussion of ABCs.
1 parent 01de89f commit a7aab8f

File tree

3 files changed

+289
-51
lines changed

3 files changed

+289
-51
lines changed

docs/source/class_basics.rst

Lines changed: 257 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -117,16 +117,15 @@ annotations have no effect at runtime:
117117
Abstract base classes and multiple inheritance
118118
**********************************************
119119

120-
Mypy uses Python abstract base classes for protocol types. There are
121-
several built-in abstract base classes types (for example,
122-
``Sequence``, ``Iterable`` and ``Iterator``). You can define abstract
123-
base classes using the ``abc.ABCMeta`` metaclass and the
124-
``abc.abstractmethod`` function decorator.
120+
Mypy supports Python abstract base classes (ABCs). Abstract classes
121+
have at least one abstract method or property that must be implemented
122+
by a subclass. You can define abstract base classes using the
123+
``abc.ABCMeta`` metaclass, and the ``abc.abstractmethod`` and
124+
``abc.abstractproperty`` function decorators. Example:
125125

126126
.. code-block:: python
127127
128128
from abc import ABCMeta, abstractmethod
129-
import typing
130129
131130
class A(metaclass=ABCMeta):
132131
@abstractmethod
@@ -140,32 +139,31 @@ base classes using the ``abc.ABCMeta`` metaclass and the
140139
def bar(self) -> str:
141140
return 'x'
142141
143-
a = A() # Error: A is abstract
144-
b = B() # OK
142+
a = A() # Error: A is abstract
143+
b = B() # OK
145144
146-
Unlike most Python code, abstract base classes are likely to play a
147-
significant role in many complex mypy programs.
145+
Note that mypy performs checking for unimplemented abstract methods
146+
even if you omit the ``ABCMeta`` metaclass. This can be useful if the
147+
metaclass would cause runtime metaclass conflicts.
148148

149149
A class can inherit any number of classes, both abstract and
150150
concrete. As with normal overrides, a dynamically typed method can
151-
implement a statically typed abstract method defined in an abstract
152-
base class.
151+
implement a statically typed method defined in any base class,
152+
including an abstract method defined in an abstract base class.
153+
154+
You can implement an abstract property using either a normal
155+
property or an instance variable.
153156

154157
.. _protocol-types:
155158

156159
Protocols and structural subtyping
157160
**********************************
158161

159-
.. note::
160-
161-
Structural subtyping is experimental. Some things may not
162-
work as expected. Mypy may pass unsafe code or it can reject
163-
valid code.
164-
165162
Mypy supports two ways of deciding whether two classes are compatible
166163
as types: nominal subtyping and structural subtyping. *Nominal*
167164
subtyping is strictly based on the class hierarchy. If class ``D``
168-
inherits class ``C``, it's also a subtype of ``C``. This form of
165+
inherits class ``C``, it's also a subtype of ``C``, and instances of
166+
``D`` can be used when ``C`` instances are expected. This form of
169167
subtyping is used by default in mypy, since it's easy to understand
170168
and produces clear and concise error messages, and since it matches
171169
how the native ``isinstance()`` check works -- based on class
@@ -174,16 +172,239 @@ a structural subtype of class ``C`` if the former has all attributes
174172
and methods of the latter, and with compatible types.
175173

176174
Structural subtyping can be seen as a static equivalent of duck
177-
typing, which is well known to Python programmers. Mypy provides an
178-
opt-in support for structural subtyping via protocol classes described
175+
typing, which is well known to Python programmers. Mypy provides
176+
support for structural subtyping via protocol classes described
179177
below. See `PEP 544 <https://www.python.org/dev/peps/pep-0544/>`_ for
180178
the detailed specification of protocols and structural subtyping in
181179
Python.
182180

181+
.. _predefined_protocols:
182+
183+
Predefined protocols
184+
********************
185+
186+
The ``typing`` module defines various protocol classes that correspond
187+
to common Python protocols, such as ``Iterable[T]``. If a class
188+
defines a suitable ``__iter__`` method, mypy understands that it
189+
implements the iterable protocol and is compatible with ``Iterable[T]``.
190+
For example, ``IntList`` below is iterable, over ``int`` values:
191+
192+
.. code-block:: python
193+
194+
from typing import Iterator, Iterable, Optional
195+
196+
class IntList:
197+
def __init__(self, value: int, next: Optional[IntList]) -> None:
198+
self.value = value
199+
self.next = next
200+
201+
def __iter__(self) -> Iterator[int]:
202+
current = self
203+
while current:
204+
yield current.value
205+
current = current.next
206+
207+
def print_numbered(items: Iterable[int]) -> None:
208+
for n, x in enumerate(items):
209+
print(n + 1, x)
210+
211+
x = IntList(3, IntList(5, None))
212+
print_numbered(x) # OK
213+
print_numbered([4, 5]) # Also OK
214+
215+
The subsections below introduce all built-in protocols defined in
216+
``typing`` and the signatures of the corresponding methods you need to define
217+
to implement each protocol (the signatures can be left out, as always, but mypy
218+
won't type check unannotated methods).
219+
220+
Iteration protocols
221+
...................
222+
223+
The iteration protocols are useful in many contexts. For example, they allow
224+
iteration of objects in for loops.
225+
226+
``Iterable[T]``
227+
---------------
228+
229+
The :ref:`example above <predefined_protocols>` has a simple implementation of an
230+
``__iter__`` method.
231+
232+
.. code-block:: python
233+
234+
def __iter__(self) -> Iterator[T]
235+
236+
``Iterator[T]``
237+
---------------
238+
239+
.. code-block:: python
240+
241+
def __next__(self) -> T
242+
def __iter__(self) -> Iterator[T]
243+
244+
Collection protocols
245+
....................
246+
247+
Many of these are implemented by built-in container types such as
248+
``list`` and ``dict``, and these are also useful for user-defined
249+
collection objects.
250+
251+
``Sized``
252+
---------
253+
254+
This is a type for objects that support ``len(x)``.
255+
256+
.. code-block:: python
257+
258+
def __len__(self) -> int
259+
260+
``Container[T]``
261+
----------------
262+
263+
This is a type for objects that support the ``in`` operator.
264+
265+
.. code-block:: python
266+
267+
def __contains__(self, x: object) -> bool
268+
269+
``Collection[T]``
270+
-----------------
271+
272+
.. code-block:: python
273+
274+
def __len__(self) -> int
275+
def __iter__(self) -> Iterator[T]
276+
def __contains__(self, x: object) -> bool
277+
278+
One-off protocols
279+
.................
280+
281+
These protocols are typically only useful with a single standard
282+
library function or class.
283+
284+
``Reversible[T]``
285+
-----------------
286+
287+
This is a type for objects that support ``reversed(x)``.
288+
289+
.. code-block:: python
290+
291+
def __reversed__(self) -> Iterator[T]
292+
293+
``SupportsAbs[T]``
294+
------------------
295+
296+
This is a type for objects that support ``abs(x)``. ``T`` is the type of
297+
value returned by ``abs(x)``.
298+
299+
.. code-block:: python
300+
301+
def __abs__(self) -> T
302+
303+
``SupportsBytes``
304+
-----------------
305+
306+
This is a type for objects that support ``bytes(x)``.
307+
308+
.. code-block:: python
309+
310+
def __bytes__(self) -> bytes
311+
312+
``SupportsComplex``
313+
-------------------
314+
315+
This is a type for objects that support ``complex(x)``.
316+
317+
.. code-block:: python
318+
319+
def __complex__(self) -> complex
320+
321+
``SupportsFloat``
322+
-----------------
323+
324+
This is a type for objects that support ``float(x)``.
325+
326+
.. code-block:: python
327+
328+
def __float__(self) -> float
329+
330+
``SupportsInt``
331+
---------------
332+
333+
This is a type for objects that support ``int(x)``.
334+
335+
.. code-block:: python
336+
337+
def __int__(self) -> int
338+
339+
``SupportsRound[T]``
340+
--------------------
341+
342+
This is a type for objects that support ``round(x)``.
343+
344+
.. code-block:: python
345+
346+
def __round__(self) -> T
347+
348+
Async protocols
349+
...............
350+
351+
These protocols can be useful in async code.
352+
353+
``Awaitable[T]``
354+
----------------
355+
356+
.. code-block:: python
357+
358+
def __await__(self) -> Generator[Any, None, T]
359+
360+
``AsyncIterable[T]``
361+
--------------------
362+
363+
.. code-block:: python
364+
365+
def __aiter__(self) -> AsyncIterator[T]
366+
367+
``AsyncIterator[T]``
368+
--------------------
369+
370+
.. code-block:: python
371+
372+
def __anext__(self) -> Awaitable[T]
373+
def __aiter__(self) -> AsyncIterator[T]
374+
375+
Context manager protocols
376+
.........................
377+
378+
There are two protocols for context managers -- one for regular context
379+
managers and one for async ones. These allow defining objects that can
380+
be used in ``with`` and ``async with`` statements.
381+
382+
``ContextManager[T]``
383+
---------------------
384+
385+
.. code-block:: python
386+
387+
def __enter__(self) -> T
388+
def __exit__(self,
389+
exc_type: Optional[Type[BaseException]],
390+
exc_value: Optional[BaseException],
391+
traceback: Optional[TracebackType]) -> Optional[bool]
392+
393+
``AsyncContextManager[T]``
394+
--------------------------
395+
396+
.. code-block:: python
397+
398+
def __aenter__(self) -> Awaitable[T]
399+
def __aexit__(self,
400+
exc_type: Optional[Type[BaseException]],
401+
exc_value: Optional[BaseException],
402+
traceback: Optional[TracebackType]) -> Awaitable[Optional[bool]]
403+
183404
Simple user-defined protocols
184405
*****************************
185406
186-
You can define a protocol class by inheriting the special
407+
You can define your own protocol class by inheriting the special
187408
``typing_extensions.Protocol`` class:
188409
189410
.. code-block:: python
@@ -216,12 +437,10 @@ similarly compatible with the protocol, as they support ``close()``.
216437
The ``Protocol`` base class is currently provided in the ``typing_extensions``
217438
package. Once structural subtyping is mature and
218439
`PEP 544 <https://www.python.org/dev/peps/pep-0544/>`_ has been accepted,
219-
``Protocol`` will be included in the ``typing`` module. Several library
220-
types such as ``typing.Sized`` and ``typing.Iterable`` will also be changed
221-
into protocols. They are currently treated as regular ABCs by mypy.
440+
``Protocol`` will be included in the ``typing`` module.
222441
223-
Defining subprotocols
224-
*********************
442+
Defining subprotocols and subclassing protocols
443+
***********************************************
225444
226445
You can also define subprotocols. Existing protocols can be extended
227446
and merged using multiple inheritance. Example:
@@ -249,7 +468,7 @@ and merged using multiple inheritance. Example:
249468
250469
Note that inheriting from an existing protocol does not automatically
251470
turn the subclass into a protocol -- it just creates a regular
252-
(non-protocol) ABC that implements the given protocol (or
471+
(non-protocol) class or ABC that implements the given protocol (or
253472
protocols). The ``typing_extensions.Protocol`` base class must always
254473
be explicitly present if you are defining a protocol:
255474
@@ -267,6 +486,13 @@ be explicitly present if you are defining a protocol:
267486
# Error: nominal subtyping used by default
268487
x: NewProtocol = Concrete() # Error!
269488
489+
You can also include default implementations of methods in
490+
protocols. If you explicitly subclass these protocols you can inherit
491+
these default implementations. Explicitly including a protocol as a
492+
base class is also a way of documenting that your class implements a
493+
particular protocol, and it forces mypy to verify that your class
494+
implementation is actually compatible with the protocol.
495+
270496
.. note::
271497
272498
You can use Python 3.6 variable annotations (`PEP 526
@@ -326,6 +552,9 @@ adds support for basic runtime structural checks:
326552
if isinstance(mug, Portable):
327553
use(mug.handles) # Works statically and at runtime
328554
555+
``isinstance()`` also works with the :ref:`predefined protocols <predefined_protocols>`
556+
in ``typing`` such as ``Iterable``.
557+
329558
.. note::
330559
``isinstance()`` with protocols is not completely safe at runtime.
331560
For example, signatures of methods are not checked. The runtime

docs/source/faq.rst

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,23 +108,24 @@ Mypy provides support for both `nominal subtyping
108108
<https://en.wikipedia.org/wiki/Nominative_type_system>`_ and
109109
`structural subtyping
110110
<https://en.wikipedia.org/wiki/Structural_type_system>`_.
111-
Support for structural subtyping is considered experimental.
112111
Some argue that structural subtyping is better suited for languages with duck
113112
typing such as Python. Mypy however primarily uses nominal subtyping,
114-
leaving structural subtyping opt-in. Here are some reasons why:
113+
leaving structural subtyping mostly opt-in (except for built-in protocols
114+
such as ``Iterable`` that always support structural subtyping). Here are some
115+
reasons why:
115116

116117
1. It is easy to generate short and informative error messages when
117118
using a nominal type system. This is especially important when
118119
using type inference.
119120

120121
2. Python provides built-in support for nominal ``isinstance()`` tests and
121122
they are widely used in programs. Only limited support for structural
122-
``isinstance()`` exists for ABCs in ``collections.abc`` and ``typing``
123-
standard library modules.
123+
``isinstance()`` is available, and it's less type safe than
124+
nominal type tests.
124125

125-
3. Many programmers are already familiar with nominal subtyping and it
126+
3. Many programmers are already familiar with static, nominal subtyping and it
126127
has been successfully used in languages such as Java, C++ and
127-
C#. Only few languages use structural subtyping.
128+
C#. Fewer languages use structural subtyping.
128129

129130
However, structural subtyping can also be useful. For example, a "public API"
130131
may be more flexible if it is typed with protocols. Also, using protocol types

0 commit comments

Comments
 (0)