Miałem tysiące problemów w życiu, a większość z nich wcale się nie zdarzyła.

Mark Twain

Możliwość tworzenia klas abstrakcyjnych i interfejsów pojawiła się w języku Python w 2007 roku wraz z wprowadzeniem PEP3119 dodającego infrastrukturę do definicji abstrakcyjnych klas. Znajomość klas abstrakcyjnych, oraz interfejsów jest konieczna do wydajnego tworzenia architektury oprogramowania stanowiąc podstawową wiedzę dla każdego programisty poważnie podchodzącego do pracy z kodem. Artykuł ten pisałem z myślą o programowaniu w języku Python 3 skupiając się na mechanizmach i ograniczeniach z nim związanych.

Interfejsy i klasy abstrakcyjne są ze sobą spokrewnione. Klasę abstrakcyjną od standardowej klasy odróżnia posiadanie jednej lub więcej abstrakcyjnych metod, zaś abstrakcyjna metoda to metoda zadeklarowana w klasie i pozbawiona definicji. W konsekwencji stworzenie instancji klasy abstrakcyjnej jest zabronione, gdyż obiekt taki miałby niezdefiniowaną metodę. W dużym uproszczeniu klasa abstrakcyjna, to klasa, która nie może mieć bezpośredniej implementacji jednocześnie mogąc zapewniać cześć implementacji. Często klasy abstrakcyjne posiadają logiczne powiązanie z obiektami po nich dziedziczącymi i stanowią ich uogólnienie. Wspomniane uogólnienie wyposaża obiekty we wspólne zmienne, oraz metody, a także wymusza określone metody współpracy z otoczeniem poprzez konieczność definicji abstrakcyjnych metod.

Do stworzenia klasy abstrakcyjnej konieczne jest wykorzystanie modułu abc.

from abc import ABC, abstractmethod

class ExampleAbstractClass(ABC):
    def __init__(self, *args, **kwargs):
        super().__init__()
        self._version = "1.0.0"

    @abstractmethod
    def do_something(self):
        pass

    def version(self):
        return sefl._version

Stworzenia obiektu ExampleAbstractClass wywoła wyjątek: TypeError: Can't instantiate abstract class ExampleAbstractClass with abstract methods do_something

Podobnie zachowają się wszystkie klasy dziedziczące po ExampleAbstractClass bez zaimplementowanej metody do_something bez względu na to czy posiadają deklaracje i definicje innych metod.

Bardzo podobny do klasy abstrakcyjnej jest intefejs. W praktyce interfejs jest klasą abstrakcyjną z obostrzeniami ograniczającymi ją do posiadania jedynie abstrakcyjnych metod. Wszystkie metody muszą być również publiczne, co w przypadku języka Python nie ma większego znaczenia. Stosowanie interfejsów wymusza na klasach je implementujących , aby posiadały niezbędne do współpracy metody. Interfejsy często używane są do do tworzenia komponentów obsługujących różne rodzaje obiektów. Przykład:

from abc import ABC, abstractmethod

class SystemInterface(ABC):
    @abstractmethod
    def open_resource(self):
        pass

class SystemA(SystemInterface):
    def open_resource(self):
        return "Definition of abstract method 'open_resource'"
    def __repr__(self):
        return self.__class__.__name__

class SystemB(SystemInterface):
    def __repr__(self):
        return self.__class__.__name__

W powyższym kodzie jedynie klasa SystemA w pełni implementuje SystemInterface i tylko jej instancja może zostać utworzona. Próba utworzenia instancji SystemInterface lub SystemB zakończy się wyjątkiem: TypeError: Can't instantiate abstract class SystemInterface with abstract methods open_resource, oraz TypeError: Can't instantiate abstract class SystemB with abstract methods open_resource

Liczę na to, że te proste przykłady zarysowały Ci czym są klasy abstrakcyjne, czym są interfejsy, oraz gdzie i jak można ich używać.


Źródła

Lektura uzupełniająca:

Artykuł dodano 2020-01-13