🌐
Python
peps.python.org › pep-0544
PEP 544 – Protocols: Structural subtyping (static duck typing) | peps.python.org
March 5, 2017 - In this PEP we specify static and runtime semantics of protocol classes that will provide a support for structural subtyping (static duck typing). Currently, PEP 484 and the typing module [typing] define abstract base classes for several common ...
🌐
Python
typing.python.org › en › latest › spec › protocol.html
Protocols — typing documentation
Specification for the Python type system » · Protocols · | Theme · Auto · Light · Dark | (Originally specified in PEP 544.) The term protocols is used for some types supporting structural subtyping.
🌐
Mypy
mypy.readthedocs.io › en › stable › protocols.html
Protocols and structural subtyping - mypy 1.19.1 documentation
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.
🌐
GitHub
github.com › python › peps › pull › 224
PEP 544: Protocols by ilevkivskyi · Pull Request #224 · python/peps
I believe David is more skeptical of this PEP than Jukka and I. But even so, the extra frustrating thing is that, indeed, the PEP process (by convention at least) prefers to have a reference implementation to support a proposal, without any guarantees that the reference implementation will ever be deployed. This is similar to the RFC-based IETF standardization process for internet protocols -- and the similarity is not coincidental, we modeled Python's PEP process after the RFC process (with which several core Python devs were highly familiar between 1995-2000).
Author   python
🌐
Python
peps.python.org › pep-0001
PEP 1 – PEP Purpose and Guidelines | peps.python.org
PEP stands for Python Enhancement Proposal. A PEP is a design document providing information to the Python community, or describing a new feature for Python or its processes or environment.
🌐
Hashnode
fronkan.hashnode.dev › a-first-look-at-python-protocols-pep-544
A First Look at Python Protocols (PEP 544) - Fredrik Sjöstrand
October 5, 2020 - @runtime_checkable class Printable(Protocol): @abstractmethod def print(self) -> None: raise NotImplementedError ... PEP 544 gives us protocols that allow us to define what requirements a function or class has for a parameter.
🌐
Medium
medium.com › @commbigo › python-typing-protocol-c2f6a60c0ac6
Python typing — Protocol
December 28, 2023 - Python typing — Protocol We all know typing in python becomes important. Now, we introduce protocol defined in pep-544 and release in python 3.8. Sometimes, we hit the exception “AttributeError …
🌐
Python
peps.python.org › pep-0813
PEP 813 – The Pretty Print Protocol | peps.python.org
3 weeks ago - This PEP describes the “pretty print protocol”, a collection of changes proposed to make pretty printing more customizable and convenient.
🌐
Python
peps.python.org
PEP 0 – Index of Python Enhancement Proposals (PEPs) | peps.python.org
This PEP contains the index of all Python Enhancement Proposals, known as PEPs. PEP numbers are assigned by the PEP editors, and once assigned are never changed. The version control history of the PEP texts represent their historical record.
Find elsewhere
🌐
DEV Community
dev.to › fronkan › a-first-look-at-python-protocols-pep-544-24bn
A First Look at Python Protocols (PEP 544) - DEV Community
July 19, 2022 - @runtime_checkable class Printable(Protocol): @abstractmethod def print(self) -> None: raise NotImplementedError ... PEP 544 gives us protocols that allow us to define what requirements a function or class has for a parameter.
🌐
Python
peps.python.org › pep-0008
PEP 8 – Style Guide for Python Code | peps.python.org
PEP 207 indicates that reflexivity rules are assumed by Python. Thus, the interpreter may swap y > x with x < y, y >= x with x <= y, and may swap the arguments of x == y and x != y. The sort() and min() operations are guaranteed to use the < ...
Top answer
1 of 8
65

New in Python 3.8:

Some of the benefits of interfaces and protocols are type hinting during the development process using tools built into IDEs and static type analysis for detection of errors before runtime. This way, a static analysis tool can tell you when you check your code if you're trying to access any members that are not defined on an object, instead of only finding out at runtime.

The typing.Protocol class was added to Python 3.8 as a mechanism for "structural subtyping." The power behind this is that it can be used as an implicit base class. That is, any class that has members that match the Protocol's defined members is considered to be a subclass of it for purposes of static type analysis.

The basic example given in PEP 544 shows how this can be used.

Copyfrom typing import Protocol

class SupportsClose(Protocol):
    def close(self) -> None:
        # ...

class Resource:
    # ...
    def close(self) -> None:
        self.file.close()
        self.lock.release()

def close_all(things: Iterable[SupportsClose]) -> None:
    for thing in things:
        thing.close()

file = open('foo.txt')
resource = Resource()
close_all([file, resource])  # OK!
close_all([1])     # Error: 'int' has no 'close' method

Note: The typing-extensions package backports typing.Protocol for Python 3.5+.

2 of 8
21

In short, you probably don't need to worry about it at all. Since Python uses duck typing - see also the Wikipedia article for a broader definition - if an object has the right methods, it will simply work, otherwise exceptions will be raised.

You could possibly have a Piece base class with some methods throwing NotImplementedError to indicate they need to be re-implemented:

Copyclass Piece(object):

    def move(<args>):
        raise NotImplementedError(optional_error_message) 

class Queen(Piece):

    def move(<args>):
        # Specific implementation for the Queen's movements

# Calling Queen().move(<args>) will work as intended but 

class Knight(Piece):
    pass

# Knight().move() will raise a NotImplementedError

Alternatively, you could explicitly validate an object you receive to make sure it has all the right methods, or that it is a subclass of Piece by using isinstance or isubclass. Note that checking the type may not be considered "Pythonic" by some and using the NotImplementedError approach or the abc module - as mentioned in this very good answer - could be preferable.

Your factory just has to produce instances of objects having the right methods on them.

🌐
GitHub
github.com › fluentpython › protocol_examples
GitHub - fluentpython/protocol_examples: A PEP 544 protocol to support type hints for functions that sort
A PEP 544 protocol to support type hints for functions that sort - fluentpython/protocol_examples
Author   fluentpython
🌐
Python
typing.python.org › en › latest › reference › protocols.html
Protocols and structural subtyping — typing documentation
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.
🌐
Python.org
discuss.python.org › peps
PEP 813 - The Pretty Print Protocol - PEPs - Discussions on Python.org
1 month ago - A couple of the elder statesmen are happy to announce PEP 813, a proposal to build-in optional pretty printing for print(), str.format(), and f-strings, and to define a protocol classes can implement to participate in and customize how their instances are pretty printed.
🌐
Nickypy
nickypy.com › blog › python-protocols
Notes on Python Protocols
Protocols in Python (PEP 544) allow for statically checking whether an object implements a specific method (see interfaces in Go, or traits in Rust).
🌐
Simon Willison
til.simonwillison.net › python › protocols
Protocols in Python | Simon Willison’s TILs
July 26, 2023 - That reveal_type(row) line will raise an error if you run the code using python and not mypy. The fix for that looks like this: from typing import TYPE_CHECKING ... if TYPE_CHECKING: reveal_type(obj) PEP 544 – Protocols: Structural subtyping (static duck typing)
🌐
Sarahabd
sarahabd.com › sarah abderemane's website › til › python protocol typing
TIL: python Protocol and typing
December 18, 2024 - Protocol was created in Python 3.8 with the PEP 544. There a multiple protocols in python but the one I’m talking about is a way to define structural typing. Some of you will also call that implicit interface. We can use the Protocol class from the typing module.
🌐
Python
peps.python.org › pep-0519
PEP 519 – Adding a file system path protocol | peps.python.org
This PEP proposes a protocol for classes which represent a file system path to be able to provide a str or bytes representation. Changes to Python’s standard library are also proposed to utilize this protocol where appropriate to facilitate ...
Top answer
1 of 1
2

After discussing a bit in the question comments and checking a pull request addressing the example of the question I can understand now why the example is correct and where my reasoning was off. Here it goes:

Typical case: checking an instance against a Protocol

Let's expand the example a bit to consider the more common case of checking if an instance of C is an implementation of ProtoA or ProtoB:

c: ProtoA = C()  # OK
c: ProtoB = C()  # Type check error, signature don't match!

So, clearly, and as expected, an instance of C is an implementation of ProtoA because the promise of ProtoA is that any implementation of it will have a method meth that can be called as c.meth(2) (2 can be any other integer in this case), and I can clearly do:

c.meth(2)  # This is correct according to the signature/type hints.

Given case: checking a class against a Protocol

So, what happens in the given example? What happens is that C has a method meth but it's not defined as a class method, so, C.meth has a different signature than c.meth, in fact, C.meth has the signature that is promised by ProtoB, and not by ProtoA, because to use C.meth directly from the class, I need to pass an argument to satisfy self, which has implicit type Any:

# This...
c = C()
c.meth(2)
# ...is equivalent to this.
c = C()
C.meth(c, 2)

# But the promise is fulfilled with anything as first argument
# because there is no explicit type hint for `self` and thus it is
# implicityly typed as `Any`.
C.meth('anything is fine here', 2)  # this is a correct call*

# *although it might result in an error depending on the implementation 
# if the `self` argument had runtime requirements not expressed in the 
# type hint.

So there it is, it had a simple explanation after all.