Python Protocols: Leveraging Structural Subtyping

Python Protocols: Leveraging Structural Subtyping
by:
blow post content copied from  Real Python
click here to view original post


In Python, a protocol specifies the methods and attributes that a class must implement to be considered of a given type. Protocols are important in Python’s type hint system, which allows for static type checking through external tools, such as mypy, Pyright, and Pyre.

Before there were protocols, these tools could only check for nominal subtyping based on inheritance. There was no way to check for structural subtyping, which relies on the internal structure of classes. This limitation affected Python’s duck typing system, which allows you to use objects without considering their nominal types. Protocols overcome this limitation, making static duck typing possible.

In this tutorial, you’ll:

  • Gain clarity around the use of the term protocol in Python
  • Learn how type hints facilitate static type checking
  • Learn how protocols allow static duck typing
  • Create custom protocols with the Protocol class
  • Understand the differences between protocols and abstract base classes

To get the most out of this tutorial, you’ll need to know the basics of object-oriented programming in Python, including concepts such as classes and inheritance. You should also know about type checking and duck typing in Python.

The Meaning of “Protocol” in Python

During Python’s evolution, the term protocol became overloaded with two subtly different meanings. The first meaning refers to internal protocols, such as the iterator, context manager, and descriptor protocols.

These protocols are widely understood in the community and consist of special methods that make up a given protocol. For example, the .__iter__() and .__next__() methods define the iterator protocol.

Python 3.8 introduced a second, slightly different type of protocol. These protocols specify the methods and attributes that a class must implement to be considered of a given type. So, these protocols also have to do with a class’s internal structure.

With this kind of protocol, you can define interchangeable classes as long as they share a common internal structure. This feature allows you to enforce a relationship between types or classes without the burden of inheritance. This relationship is known as structural subtyping or static duck typing.

In this tutorial, you’ll focus on this second meaning of the term protocol. First, you’ll have a look at how Python manages types.

Dynamic and Static Typing in Python

Python is a dynamically typed language, which means that the Python interpreter checks an object’s type when the code runs. It also means that while a variable can only reference one object at a time, the type of that object can change during the variable’s lifetime.

For example, you can have a variable that starts as a string and changes into an integer number:

Python
>>> value = "One hundred"
>>> value
'One hundred'

>>> value = 100
>>> value
100

In this example, you have a variable that starts as a string. Later in your code, you change the variable’s value to an integer.

Because of its dynamic nature, Python has embraced a flexible typing system that’s known as duck typing.

Duck Typing

Duck typing is a type system in which an object is considered compatible with a given type if it has all the methods and attributes that the type requires. This typing system supports the ability to use objects of independent and decoupled classes in a specific context as long as they adhere to some common interface.

As an example of duck typing, you can consider built-in container data types, such as lists, tuples, strings, dictionaries, and sets. All of these data types support iteration:

Python
>>> numbers = [1, 2, 3]
>>> person = ("Jane", 25, "Python Dev")
>>> letters = "abc"
>>> ordinals = {"one": "first", "two": "second", "three": "third"}
>>> even_digits = {2, 4, 6, 8}

>>> containers = [numbers, person, letters, ordinals, even_digits]

>>> for container in containers:
...     for element in container:
...         print(element, end=" ")
...     print()
...
1 2 3 
Jane 25 Python Dev 
a b c 
one two three 
8 2 4 6 

In this code snippet, you define a few variables using different built-in types. Then, you start a for loop over the collections and iterate over each of them to print their elements to the screen. Even though the built-in types are significantly different from one another, they all support iteration.

The duck typing system allows you to create code that can work with different objects, provided that they share a common interface. This system allows you to set relationships between classes that don’t rely on inheritance, which produces flexible and decoupled code.

Read the full article at https://realpython.com/python-protocol/ »


[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]


July 17, 2024 at 07:30PM
Click here for more details...

=============================
The original post is available in Real Python by
this post has been published as it is through automation. Automation script brings all the top bloggers post under a single umbrella.
The purpose of this blog, Follow the top Salesforce bloggers and collect all blogs in a single place through automation.
============================

Salesforce