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ć.
Lektura uzupełniająca: