Jak mogę zrobić streszczenie klasy lub metody w Pythonie?
Próbowałem przedefiniować __new__()
tak:
class F:
def __new__(cls):
raise Exception("Unable to create an instance of abstract class %s" %cls)
ale teraz, jeśli utworzę klasę, G
która odziedziczy po niej F
:
class G(F):
pass
nie mogę też utworzyć instancji G
, ponieważ wywołuje __new__
metodę superklasy.
Czy istnieje lepszy sposób zdefiniowania klasy abstrakcyjnej?
python
class
inheritance
abstract-class
abstract
Martin Thoma
źródło
źródło
Odpowiedzi:
Użyj
abc
modułu, aby utworzyć klasy abstrakcyjne. Użyjabstractmethod
dekoratora, aby zadeklarować streszczenie metody, i zadeklaruj streszczenie klasy na jeden z trzech sposobów, w zależności od wersji Pythona.W Pythonie 3.4 i nowszych możesz dziedziczyć po
ABC
. We wcześniejszych wersjach Pythona musisz określić metaklasę swojej klasy jakoABCMeta
. Określanie metaklasy ma inną składnię w Pythonie 3 i Pythonie 2. Trzy możliwości pokazano poniżej:Niezależnie od tego, jakiego użyjesz, nie będziesz w stanie utworzyć instancji klasy abstrakcyjnej, która ma metody abstrakcyjne, ale będziesz w stanie utworzyć instancję podklasy, która zapewnia konkretne definicje tych metod:
źródło
@abstractmethod
sprawia, że funkcja dekorowana musi zostać zastąpiona przed utworzeniem instancji klasy. Z dokumentów:A class that has a metaclass derived from ABCMeta cannot be instantiated unless all of its abstract methods and properties are overridden.
@abstractmethod
do__init__
sposobu jak dobrze zobaczyć stackoverflow.com/q/44800659/547270Starym sposobem (wcześniejszym niż PEP 3119 ) jest to po prostu
raise NotImplementedError
w klasie abstrakcyjnej, gdy wywoływana jest metoda abstrakcyjna.To nie ma tych samych dobrych właściwości, co przy użyciu
abc
modułu. Nadal możesz utworzyć instancję samej abstrakcyjnej klasy bazowej i nie znajdziesz swojego błędu, dopóki nie wywołasz metody abstrakcyjnej w czasie wykonywania.Ale jeśli masz do czynienia z niewielkim zestawem prostych klas, być może za pomocą kilku abstrakcyjnych metod, takie podejście jest nieco łatwiejsze niż próba przebicia się przez
abc
dokumentację.źródło
Oto bardzo prosty sposób bez konieczności zajmowania się modułem ABC.
W
__init__
metodzie klasy, która ma być klasą abstrakcyjną, można sprawdzić „typ” jaźni. Jeśli typem self jest klasa podstawowa, wówczas osoba dzwoniąca próbuje utworzyć instancję klasy podstawowej, więc zgłosz wyjątek. Oto prosty przykład:Po uruchomieniu tworzy:
To pokazuje, że można utworzyć instancję podklasy, która dziedziczy z klasy podstawowej, ale nie można bezpośrednio utworzyć instancji klasy podstawowej.
źródło
Większość poprzednich odpowiedzi była poprawna, ale oto odpowiedź i przykład dla Pythona 3.7. Tak, możesz stworzyć abstrakcyjną klasę i metodę. Dla przypomnienia czasami klasa powinna zdefiniować metodę, która logicznie należy do klasy, ale klasa ta nie może określić, w jaki sposób zaimplementować metodę. Na przykład w poniższych zajęciach z rodzicami i dziećmi jedzą oboje, ale ich realizacja będzie różna dla każdego, ponieważ niemowlęta i rodzice jedzą inny rodzaj jedzenia, a liczba posiłków jest inna. Tak więc, podklasy metod jeść zastępują AbstractClass.eat.
WYNIK:
źródło
import abc
jest bezużyteczny.Ten będzie działał w Pythonie 3
źródło
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
:Nasza
Base
klasa zawsze będzie miała afrom_dict
classmethod
, aproperty
prop1
(która jest tylko do odczytu) i aproperty
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
: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
(tutaji_am_not_abstract
:).Teraz możemy zrobić:
Zgodnie z życzeniem nie możemy ustawić
prop1
:wróci
Również nasza
from_dict
metoda działa dobrze:Gdybyśmy teraz zdefiniowali taką drugą klasę
B
:i próbował utworzyć instancję takiego obiektu:
dostaniemy błąd
wymieniając wszystkie rzeczy, w
Base
których nie wdrożyliśmyB
.źródło
to również działa i jest proste:
źródło
Możesz także wykorzystać metodę __new__ na swoją korzyść. Właśnie o czymś zapomniałeś. Metoda __new__ zawsze zwraca nowy obiekt, dlatego musisz zwrócić nową metodę jego nadklasy. Wykonaj następujące czynności.
Korzystając z nowej metody, musisz zwrócić obiekt, a nie słowo kluczowe Brak. To wszystko, za czym tęskniłeś.
źródło
Uważam, że przyjęta odpowiedź, a wszystkie inne dziwne, ponieważ przechodzą
self
do klasy abstrakcyjnej. Klasa abstrakcyjna nie jest tworzona, więc nie może mieć klasyself
.Więc spróbuj tego, to działa.
źródło
źródło
We fragmencie kodu można również rozwiązać ten problem, podając implementację
__new__
metody w podklasie, podobnie:Ale to jest hack i odradzam ci to, chyba że wiesz, co robisz. W prawie wszystkich przypadkach radzę korzystać z
abc
modułu, który inni wcześniej sugerowali.Również podczas tworzenia nowej klasy (baza), sprawiają, że podklasy
object
, tak:class MyBaseClass(object):
. Nie wiem, czy jest to już tak znaczące, ale pomaga zachować spójność stylu w kodzieźródło
Szybki dodatek do old-schoolowej odpowiedzi @ TimGilbert ... możesz sprawić, że metoda init () abstrakcyjnej klasy podstawowej będzie generować wyjątek, co uniemożliwiłoby jej utworzenie, nie?
źródło