@@ -158,30 +158,32 @@ Protocols and structural subtyping
158158
159159.. note ::
160160
161- The support for structural subtyping is still experimental. Some features
162- might be not yet implemented, mypy could pass unsafe code or reject
163- working code.
164-
165- There are two main type systems with respect to subtyping: nominal subtyping
166- and structural subtyping. The *nominal * subtyping is based on class hierarchy,
167- so that if class ``D `` inherits from class ``C ``, then it is a subtype
168- of ``C ``. This type system is primarily used in mypy since it allows
169- to produce clear and concise error messages, and since Python provides native
170- ``isinstance() `` checks based on class hierarchy. The *structural * subtyping
171- however has its own advantages. In this system class ``D `` is a subtype
172- of class ``C `` if the former has all attributes of the latter with
173- compatible types.
174-
175- This type system is a static equivalent of duck typing, well known by Python
176- programmers. Mypy provides an opt-in support for structural subtyping via
177- protocol classes described in this section.
178- See `PEP 544 <https://www.python.org/dev/peps/pep-0544/ >`_ for
179- specification of protocols and structural subtyping in Python.
180-
181- User defined protocols
182- **********************
183-
184- To define a protocol class, one must inherit the special
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+
165+ Mypy supports two ways of deciding whether two classes are compatible
166+ as types: nominal subtyping and structural subtyping. *Nominal *
167+ 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
169+ subtyping is used by default in mypy, since it's easy to understand
170+ and produces clear and concise error messages, and since it matches
171+ how the native ``isinstance() `` check works -- based on class
172+ hierarchy. *Structural * subtyping can also be useful. Class ``D `` is
173+ a structural subtype of class ``C `` if the former has all attributes
174+ and methods of the latter, and with compatible types.
175+
176+ 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
179+ below. See `PEP 544 <https://www.python.org/dev/peps/pep-0544/ >`_ for
180+ the detailed specification of protocols and structural subtyping in
181+ Python.
182+
183+ Simple user-defined protocols
184+ *****************************
185+
186+ You can define a protocol class by inheriting the special
185187``typing_extensions.Protocol `` class:
186188
187189.. code-block :: python
@@ -191,37 +193,42 @@ To define a protocol class, one must inherit the special
191193
192194 class SupportsClose (Protocol ):
193195 def close (self ) -> None :
194- ...
196+ ... # Explicit '...'
197+
198+ class Resource : # No SupportsClose base class!
199+ # ... some methods ...
195200
196- class Resource : # Note, this class does not have 'SupportsClose' base.
197- # some methods
198201 def close (self ) -> None :
199202 self .resource.release()
200203
201- def close_all (things : Iterable[SupportsClose]) -> None :
202- for thing in things :
203- thing .close()
204+ def close_all (items : Iterable[SupportsClose]) -> None :
205+ for item in items :
206+ item .close()
204207
205- close_all([Resource(), open (' some/file' )]) # This passes type check
208+ close_all([Resource(), open (' some/file' )]) # Okay!
209+
210+ ``Resource `` is a subtype of the ``SupportClose `` protocol since it defines
211+ a compatible ``close `` method. Regular file objects returned by ``open() `` are
212+ similarly compatible with the protocol, as they support ``close() ``.
206213
207214.. note ::
208215
209- The ``Protocol `` base class is currently provided in ``typing_extensions ``
210- package. When structural subtyping is mature and
211- `PEP 544 <https://www.python.org/dev/peps/pep-0544/ >`_ is accepted,
212- ``Protocol `` will be included in the ``typing `` module. As well, several
213- types such as ``typing.Sized ``, ``typing.Iterable `` etc. will be made
214- protocols.
216+ The ``Protocol `` base class is currently provided in the ``typing_extensions ``
217+ package. Once structural subtyping is mature and
218+ `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 .
215222
216223Defining subprotocols
217224*********************
218225
219- Subprotocols are also supported . Existing protocols can be extended
220- and merged using multiple inheritance. For example :
226+ You can also define subprotocols . Existing protocols can be extended
227+ and merged using multiple inheritance. Example :
221228
222229.. code-block :: python
223230
224- # continuing from previous example
231+ # ... continuing from the previous example
225232
226233 class SupportsRead (Protocol ):
227234 def read (self , amount : int ) -> bytes : ...
@@ -232,46 +239,47 @@ and merged using multiple inheritance. For example:
232239 class AdvancedResource (Resource ):
233240 def __init__ (self , label : str ) -> None :
234241 self .label = label
242+
235243 def read (self , amount : int ) -> bytes :
236244 # some implementation
237245 ...
238246
239- resource = None # type: TaggedReadableResource
240-
241- # some code
242-
247+ resource: TaggedReadableResource
243248 resource = AdvancedResource(' handle with care' ) # OK
244249
245- Note that inheriting from existing protocols does not automatically turn
246- a subclass into a protocol, it just creates a usual (non-protocol) ABC that
247- implements given protocols. The ``typing_extensions.Protocol `` base must always
248- be explicitly present:
250+ Note that inheriting from an existing protocol does not automatically
251+ turn the subclass into a protocol -- it just creates a regular
252+ (non-protocol) ABC that implements the given protocol (or
253+ protocols). The ``typing_extensions.Protocol `` base class must always
254+ be explicitly present if you are defining a protocol:
249255
250256.. code-block :: python
251257
252258 class NewProtocol (SupportsClose ): # This is NOT a protocol
253259 new_attr: int
254260
255261 class Concrete :
256- new_attr = None # type: int
262+ new_attr: int = 0
263+
257264 def close (self ) -> None :
258265 ...
259- # Below is an error, since nominal subtyping is used by default
260- x = Concrete() # type: NewProtocol # Error!
266+
267+ # Error: nominal subtyping used by default
268+ x: NewProtocol = Concrete() # Error!
261269
262270 .. note ::
263271
264- The `PEP 526 <https://www.python.org/dev/peps/pep-0526/ >`_ variable
265- annotations can be used to declare protocol attributes. However, protocols
266- are also supported on Python 2.7 and Python 3.3+ with the help of type
267- comments and properties, see
268- `backwards compatibility in PEP 544 <https://www.python.org/dev/peps/pep-0544/#backwards-compatibility >`_.
272+ You can use Python 3.6 variable annotations (`PEP 526
273+ <https://www.python.org/dev/peps/pep-0526/> `_)
274+ to declare protocol attributes. On Python 2.7 and earlier Python 3
275+ versions you can use type comments and properties.
269276
270277Recursive protocols
271278*******************
272279
273- Protocols can be recursive and mutually recursive. This could be useful for
274- declaring abstract recursive collections such as trees and linked lists:
280+ Protocols can be recursive (self-referential) and mutually
281+ recursive. This is useful for declaring abstract recursive collections
282+ such as trees and linked lists:
275283
276284.. code-block :: python
277285
@@ -280,8 +288,10 @@ declaring abstract recursive collections such as trees and linked lists:
280288
281289 class TreeLike (Protocol ):
282290 value: int
291+
283292 @ property
284293 def left (self ) -> Optional[' TreeLike' ]: ...
294+
285295 @ property
286296 def right (self ) -> Optional[' TreeLike' ]: ...
287297
@@ -296,9 +306,9 @@ declaring abstract recursive collections such as trees and linked lists:
296306 Using ``isinstance() `` with protocols
297307*************************************
298308
299- To use a protocol class with ``isinstance() ``, one needs to decorate it with
300- a special ``typing_extensions.runtime `` decorator. It will add support for
301- basic runtime structural checks:
309+ You can use a protocol class with ``isinstance() `` if you decorate it
310+ with the ``typing_extensions.runtime `` class decorator. The decorator
311+ adds support for basic runtime structural checks:
302312
303313.. code-block :: python
304314
@@ -314,11 +324,9 @@ basic runtime structural checks:
314324
315325 mug = Mug()
316326 if isinstance (mug, Portable):
317- use(mug.handles) # Works statically and at runtime.
327+ use(mug.handles) # Works statically and at runtime
318328
319329 .. note ::
320- ``isinstance() `` is with protocols not completely safe at runtime.
330+ ``isinstance() `` with protocols is not completely safe at runtime.
321331 For example, signatures of methods are not checked. The runtime
322- implementation only checks the presence of all protocol members
323- in object's MRO.
324-
332+ implementation only checks that all protocol members are defined.
0 commit comments