Jak wyjaśniono w innych odpowiedziach, tak, możesz używać klas abstrakcyjnych w Pythonie za pomocą abc
modułu . Poniżej podam rzeczywisty przykład z wykorzystaniem streszczenia @classmethod
, @property
oraz@abstractmethod
(przy użyciu Python 3.6+). Dla mnie zwykle łatwiej jest zacząć od przykładów, które mogę łatwo skopiować i wkleić; Mam nadzieję, że ta odpowiedź będzie przydatna także dla innych.
Utwórzmy najpierw klasę podstawową o nazwie Base
:
from abc import ABC, abstractmethod
class Base(ABC):
@classmethod
@abstractmethod
def from_dict(cls, d):
pass
@property
@abstractmethod
def prop1(self):
pass
@property
@abstractmethod
def prop2(self):
pass
@prop2.setter
@abstractmethod
def prop2(self, val):
pass
@abstractmethod
def do_stuff(self):
pass
Nasza Base
klasa zawsze będzie miała a from_dict
classmethod
, a property
prop1
(która jest tylko do odczytu) i a property
prop2
(którą można również ustawić), a także wywoływaną funkcję do_stuff
. Niezależnie od tego, na jakiej podstawie zbudowana jest teraz klasa, Base
trzeba będzie zaimplementować wszystkie te metody / właściwości. Pamiętaj, że aby metoda była abstrakcyjna, wymagane są dwa elementy dekoracyjne - classmethod
i abstrakcyjneproperty
.
Teraz możemy stworzyć taką klasę A
:
class A(Base):
def __init__(self, name, val1, val2):
self.name = name
self.__val1 = val1
self._val2 = val2
@classmethod
def from_dict(cls, d):
name = d['name']
val1 = d['val1']
val2 = d['val2']
return cls(name, val1, val2)
@property
def prop1(self):
return self.__val1
@property
def prop2(self):
return self._val2
@prop2.setter
def prop2(self, value):
self._val2 = value
def do_stuff(self):
print('juhu!')
def i_am_not_abstract(self):
print('I can be customized')
Wszystkie wymagane metody / właściwości są zaimplementowane i możemy - oczywiście - również dodać dodatkowe funkcje, które nie są częścią Base
(tutaj i_am_not_abstract
:).
Teraz możemy zrobić:
a1 = A('dummy', 10, 'stuff')
a2 = A.from_dict({'name': 'from_d', 'val1': 20, 'val2': 'stuff'})
a1.prop1
# prints 10
a1.prop2
# prints 'stuff'
Zgodnie z życzeniem nie możemy ustawić prop1
:
a.prop1 = 100
wróci
AttributeError: nie można ustawić atrybutu
Również nasza from_dict
metoda działa dobrze:
a2.prop1
# prints 20
Gdybyśmy teraz zdefiniowali taką drugą klasę B
:
class B(Base):
def __init__(self, name):
self.name = name
@property
def prop1(self):
return self.name
i próbował utworzyć instancję takiego obiektu:
b = B('iwillfail')
dostaniemy błąd
TypeError: Nie można utworzyć instancji klasy abstrakcyjnej B za pomocą metod abstrakcyjnych do_stuff, from_dict, prop2
wymieniając wszystkie rzeczy, w Base
których nie wdrożyliśmy B
.