3 quick notes about type checking in Python
I’m going to give you three quick pieces of information about type checking in Python.
# 1. Forward references
Forward references help you refer to a type even when that has not been declared yet. They are string literals expressing a type. They are mostly used when a class needs to refer to itself, eg.:
Example - a row of houses in a street:
class RowHouse:
def __init__(self, left_neighbor: 'RowHouse', right_neighbor: 'RowHouse'):
...
# 2. Stub files
You might have encountered the word stub files while working with mypy
.
Stub files help the type checker analyse the code statically, but they are not run by the interpreter. Their syntax is the same as for regular Python code.
There are a few reasons why one might need stub files, most importantly when working with third-party modules where type hints have not been written yet.
# 3. Structural subtyping
You might have read about “duck typing”. The good news is that Python allows “static duck typing”, also known as structural subtyping, which means that a class doesn’t necessarily have to inherit from a parent class to be considered a subclass - if it implements the same methods, it will be considered a structural subclass.
from typing_extensions import Protocol
class MyType(Protocol):
def boom(self):
...
class MyOtherType:
def boom(self):
pass
def my_function(arg: MyType) -> None:
pass
other_type = MyOtherType()
my_function(other_type)
Note that mypy
will not complain about the last line, because MyOtherType implements the MyType
protocol, even without inheriting from it. This is similar to abstract base classes, except that a protocol has no implementation (an abstract base class can define implentations of the methods), and while Protocols are not enforced at runtime, while abstract base classes provide runtime safety.
Resources:
- PEP-0484
- PEP-0483
- Python docs
- Mark McDonnell’s excellent blogpost