ProtocolsΒΆ
typing.Protocol allows to define your own abstract type, to enforce a custom
behavioral interface.
Exercise (easy)
Use a protocol for a math object that has a norm() method.
1from collections.abc import ...
2from typing import Protocol
3import math
4
5
6class Normable(Protocol):
7 def norm(self) -> float: ...
8
9
10def is_unit(obj: ...) -> bool:
11 return math.isclose(obj.norm(), 1.0)
12
13
14class Vector:
15 def __init__(self, coefficents: ...) -> None:
16 self._coefficients: list[float] = list(coefficents)
17
18 def norm(self) -> float:
19 return math.sqrt(sum(coefficient**2 for coefficient in self._coefficients))
Correction
It is not mandatory to inherit from
Normablein the definition ofVector. Doing so enables to trigger an error at the line of vector instantiation if theVectorclass has not implemented thenormmethod.
1from collections.abc import Sequence
2from typing import Protocol
3import math
4
5
6class Normable(Protocol):
7 def norm(self) -> float: ...
8
9
10def is_unit(obj: Normable) -> bool:
11 return math.isclose(obj.norm(), 1.0)
12
13
14class Vector:
15 def __init__(self, coefficents: Sequence[float]) -> None:
16 self._coefficients: list[float] = list(coefficents)
17
18 def norm(self) -> float:
19 return math.sqrt(sum(coefficient**2 for coefficient in self._coefficients))
20
21class VectorNoNorm:
22 def __init__(self, coefficents: Sequence[float]) -> None:
23 self._coefficients: list[float] = list(coefficents)
24
25
26class VectorNoNorm_(Normable):
27 def __init__(self, coefficents: Sequence[float]) -> None:
28 self._coefficients: list[float] = list(coefficents)
29
30vector = Vector((3.0, 4.0))
31vector_ = Vector({3.0, 4.0}) # not ok
32
33is_unit(vector)
34is_unit(2) # not ok
35
36vector_no_norm = VectorNoNorm((3.0, 4.0))
37is_unit(vector_no_norm) # not ok
38
39VectorNoNorm_((3.0, 4.0)) # not ok