Subtyping
To move forward, we'll need a quick interlude about subtyping.
Subtyping is a generalization of subclassing. If you're familiar with set theory, subtyping is very similar to one set being a subset of another.
Definition
A type Child
is a subtype of type Parent
if a value of type Child
can be assigned to
a variable of type Parent
Examples
-
Dog
is a subclass ofAnimal
, soDog
is also a subtype ofAnimal
-
int
andstr
are subtypes ofint | str
-
Any type is a subtype of itself
-
Literal["nice"]
is a subtype ofstr
-
A type is a subtype of a protocol if it satisfies it
class Reader(Protocol): def read_chunk(self, max_size: int) -> str: ... class StringReader: def __init__(self, initial: str) -> None: self._buffer = initial def read_chunk(self, max_size: int) -> str: max_size = max(max_size, 0) chunk = self._buffer[:max_size] self._buffer = self._buffer[max_size:] return chunk reader: Reader = StringReader("Hello, world!")
-
tuple[int, ...]
is a subtype oftuple[int | str, ...]
-
Callable[[Animal], int]
is a subtype ofCallable[[Dog], int | str]
-
list[int]
is not a subtype oflist[int | str]
Wait, what?
You'll see why later in the series!