1.2. Interface

1.2.1. Rationale

  • Python don't have interfaces

  • Cannot instantiate

  • Inheriting class must implement all methods

  • Only method declaration

  • PEP 544 Protocols: Structural subtyping (static duck typing)

interface

Software entity with public methods and attibutes declaration

implement

Class implements interface if has all public fields and methods from interface

1.2.2. Example

Listing 1.30. 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

Listing 1.31. 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

1.2.4.1. OOP Interface Define

  • Assignment name: OOP Interface Define

  • Last update: 2020-10-14

  • Complexity level: easy

  • Lines of code to write: 13 lines

  • Estimated time of completion: 13 min

  • Solution: solution/oop_interface_define.py

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 "Output" 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

Output
>>> assert hasattr(IrisInterface, 'mean')
>>> assert hasattr(IrisInterface, 'sum')
>>> assert hasattr(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

1.2.4.2. OOP Interface Implement

  • Assignment name: OOP Interface Implement

  • Last update: 2020-10-14

  • Complexity level: easy

  • Lines of code to write: 12 lines

  • Estimated time of completion: 13 min

  • Solution: solution/oop_interface_implement.py

English
  1. Use data from "Input" section (see below)

  2. Define class Setosa implementing IrisInterface

  3. Implement interface

  4. Compare result with "Output" section (see below)

Polish
  1. Użyj danych z sekcji "Input" (patrz poniżej)

  2. Stwórz klasę Setosa implementującą IrisInterface

  3. Zaimplementuj interfejs

  4. Porównaj wyniki z sekcją "Output" (patrz poniżej)

Input
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
Output
>>> assert issubclass(Setosa, IrisInterface)
>>> assert hasattr(Setosa, 'mean')
>>> assert hasattr(Setosa, 'sum')
>>> assert hasattr(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
Hints
  • self.__dict__.values()

  • mean = sum() / len()