1.2. Interface¶
1.2.1. Rationale¶
Python don't have interfaces
Cannot instantiate
Inheriting class must implement all methods
Only method declaration
Since Python 3.8: PEP 544 -- Protocols: Structural subtyping (static duck typing)
- interface
Software entity with public methods and attribute declaration
- implement
Class implements interface if has all public fields and methods from interface
1.2.2. Example¶
Interfaces:
from datetime import timedelta
class CacheInterface:
timeout: timedelta
def get(self, key: str) -> str:
raise NotImplementedError
def set(self, key: str, value: str) -> None:
raise NotImplementedError
def is_valid(self, key: str) -> bool:
raise NotImplementedError
1.2.3. Use Cases¶
Interfaces:
from datetime import timedelta
class Cache:
timeout: timedelta
def get(self, key: str) -> str:
raise NotImplementedError
def set(self, key: str, value: str) -> None:
raise NotImplementedError
def is_valid(self, key: str) -> bool:
raise NotImplementedError
class CacheDatabase(Cache):
timeout: timedelta
def is_valid(self, key: str) -> bool:
...
def get(self, key: str) -> str:
...
def set(self, key: str, value: str) -> None:
...
class CacheRAM(Cache):
timeout: timedelta
def is_valid(self, key: str) -> bool:
...
def get(self, key: str) -> str:
...
def set(self, key: str, value: str) -> None:
...
class CacheFilesystem(Cache):
timeout: timedelta
def is_valid(self, key: str) -> bool:
...
def get(self, key: str) -> str:
...
def set(self, key: str, value: str) -> None:
...
fs: Cache = CacheFilesystem()
fs.set('name', 'Jan Twardowski')
fs.is_valid('name')
fs.get('name')
ram: Cache = CacheRAM()
ram.set('name', 'Jan Twardowski')
ram.is_valid('name')
ram.get('name')
db: Cache = CacheDatabase()
db.set('name', 'Jan Twardowski')
db.is_valid('name')
db.get('name')
1.2.4. Assignments¶
"""
* Assignment: OOP Interface Define
* Complexity: easy
* Lines of code: 13 lines
* Time: 8 min
English:
1. Define interface `IrisInterface`
2. Attributes: `sepal_length, sepal_width, petal_length, petal_width`
3. Methods: `sum()`, `len()`, `mean()` in `IrisInterface`
4. All methods and constructor must raise exception `NotImplementedError`
5. Compare result with "Tests" section (see below)
Polish:
1. Zdefiniuj interfejs `IrisInterface`
2. Attributes: `sepal_length, sepal_width, petal_length, petal_width`
3. Metody: `sum()`, `len()`, `mean()` w `IrisInterface`
4. Wszystkie metody oraz konstruktor muszą podnosić wyjątek `NotImplementedError`
5. Porównaj wyniki z sekcją "Tests" (patrz poniżej)
Tests:
>>> assert hasattr(IrisInterface, 'mean')
>>> assert hasattr(IrisInterface, 'sum')
>>> assert hasattr(IrisInterface, 'len')
>>> from inspect import isfunction
>>> assert isfunction(IrisInterface.mean)
>>> assert isfunction(IrisInterface.sum)
>>> assert isfunction(IrisInterface.len)
>>> IrisInterface.__annotations__ # doctest: +NORMALIZE_WHITESPACE
{'sepal_length': <class 'float'>,
'sepal_width': <class 'float'>,
'petal_length': <class 'float'>,
'petal_width': <class 'float'>}
>>> iris = IrisInterface(5.8, 2.7, 5.1, 1.9)
Traceback (most recent call last):
NotImplementedError
"""
"""
* Assignment: OOP Interface Implement
* Complexity: easy
* Lines of code: 12 lines
* Time: 8 min
English:
1. Use data from "Given" section (see below)
2. Define class `Setosa` implementing `IrisInterface`
3. Implement interface
4. Compare result with "Tests" section (see below)
Polish:
1. Użyj danych z sekcji "Given" (patrz poniżej)
2. Stwórz klasę `Setosa` implementującą `IrisInterface`
3. Zaimplementuj interfejs
4. Porównaj wyniki z sekcją "Tests" (patrz poniżej)
Hints:
* `self.__dict__.values()`
* `mean = sum() / len()`
Tests:
>>> assert issubclass(Setosa, IrisInterface)
>>> assert hasattr(Setosa, 'mean')
>>> assert hasattr(Setosa, 'sum')
>>> assert hasattr(Setosa, 'len')
>>> from inspect import isfunction
>>> assert isfunction(Setosa.mean)
>>> assert isfunction(Setosa.sum)
>>> assert isfunction(Setosa.len)
>>> Setosa.__annotations__ # doctest: +NORMALIZE_WHITESPACE
{'sepal_length': <class 'float'>,
'sepal_width': <class 'float'>,
'petal_length': <class 'float'>,
'petal_width': <class 'float'>}
>>> setosa = Setosa(5.1, 3.5, 1.4, 0.2)
>>> setosa.len()
4
>>> setosa.sum()
10.2
>>> setosa.mean()
2.55
"""
# Given
class IrisInterface:
sepal_length: float
sepal_width: float
petal_length: float
petal_width: float
def __init__(self,
sepal_length: float,
sepal_width: float,
petal_length: float,
petal_width: float) -> None:
raise NotImplementedError
def mean(self) -> float:
raise NotImplementedError
def sum(self) -> float:
raise NotImplementedError
def len(self) -> int:
raise NotImplementedError