Jaka jest różnica między klasą abstrakcyjną a interfejsem w Pythonie?
źródło
Jaka jest różnica między klasą abstrakcyjną a interfejsem w Pythonie?
To, co czasem zobaczysz, jest następujące:
class Abstract1( object ):
"""Some description that tells you it's abstract,
often listing the methods you're expected to supply."""
def aMethod( self ):
raise NotImplementedError( "Should have implemented this" )
Ponieważ Python nie ma (i nie potrzebuje) formalnej umowy interfejsu, nie ma w tym języku rozróżnienia między abstrakcją a interfejsem. Jeśli ktoś przejdzie wysiłek zdefiniowania formalnego interfejsu, będzie to również klasa abstrakcyjna. Jedynymi różnicami byłyby określone zamiary w dokumentacji.
Różnica między abstrakcją a interfejsem polega na rozczesywaniu włosów, gdy piszesz kaczkę.
Java używa interfejsów, ponieważ nie ma wielokrotnego dziedziczenia.
Ponieważ Python ma wiele elementów dziedziczenia, możesz również zobaczyć coś takiego
class SomeAbstraction( object ):
pass # lots of stuff - but missing something
class Mixin1( object ):
def something( self ):
pass # one implementation
class Mixin2( object ):
def something( self ):
pass # another
class Concrete1( SomeAbstraction, Mixin1 ):
pass
class Concrete2( SomeAbstraction, Mixin2 ):
pass
Wykorzystuje to rodzaj abstrakcyjnej nadklasy z mixinami, aby utworzyć konkretne podklasy, które są rozłączne.
NotImplementedError("Class %s doesn't implement aMethod()" % (self.__class__.__name__))
jest bardziej informacyjny komunikat o błędzie :)Interfejs dla obiektu to zestaw metod i atrybutów tego obiektu.
W Pythonie możemy użyć abstrakcyjnej klasy bazowej do zdefiniowania i wymuszenia interfejsu.
Korzystanie z abstrakcyjnej klasy bazowej
Powiedzmy, że chcemy użyć jednej z abstrakcyjnych klas podstawowych z
collections
modułu:Jeśli spróbujemy go użyć, otrzymamy,
TypeError
ponieważ utworzona przez nas klasa nie obsługuje oczekiwanego zachowania zestawów:Więc jesteśmy zobowiązani do wdrożenia w najmniej
__contains__
,__iter__
i__len__
. Skorzystajmy z tego przykładu implementacji z dokumentacji :Implementacja: Tworzenie abstrakcyjnej klasy bazowej
Możemy stworzyć własną Abstrakcyjną Klasę Podstawową, ustawiając metaklasę
abc.ABCMeta
i używającabc.abstractmethod
dekoratora na odpowiednich metodach. Metaklasa zostanie dodana udekorowane funkcje do__abstractmethods__
atrybutu, zapobiegając tworzeniu wystąpień, dopóki nie zostaną zdefiniowane.Na przykład „efektywny” jest definiowany jako coś, co można wyrazić słowami. Powiedzmy, że chcieliśmy zdefiniować abstrakcyjną klasę bazową, która jest efektywna, w Pythonie 2:
Lub w Pythonie 3, z niewielką zmianą deklaracji metaklasy:
Teraz, jeśli spróbujemy stworzyć efektowny obiekt bez implementacji interfejsu:
i spróbuj utworzyć go:
Mówi się nam, że nie zakończyliśmy pracy.
Teraz, jeśli zastosujemy się do tego, zapewniając oczekiwany interfejs:
jesteśmy w stanie użyć konkretnej wersji klasy pochodzącej z abstrakcyjnej:
Są inne rzeczy, które moglibyśmy z tym zrobić, np. Zarejestrować wirtualne podklasy, które już implementują te interfejsy, ale myślę, że to wykracza poza zakres tego pytania. Inne metody przedstawione tutaj musiałyby dostosować tę metodę za pomocą
abc
modułu.Wniosek
Wykazaliśmy, że utworzenie abstrakcyjnej klasy bazowej definiuje interfejsy dla obiektów niestandardowych w języku Python.
źródło
Python> = 2.6 ma abstrakcyjne klasy podstawowe .
Istnieje również moduł interfejsu Zope , który jest używany w projektach poza Zope , takich jak skręcone. Nie jestem do końca zaznajomiony z tym, ale tutaj jest strona wiki , która może pomóc.
Ogólnie rzecz biorąc, nie potrzebujesz koncepcji klas abstrakcyjnych ani interfejsów w Pythonie (edytowane - patrz odpowiedź S.Lott, aby uzyskać szczegółowe informacje).
źródło
Python tak naprawdę nie ma żadnej koncepcji.
Używa pisania kaczego, co eliminuje potrzebę interfejsów (przynajmniej dla komputera :-))
Python <= 2.5: Klasy podstawowe oczywiście istnieją, ale nie ma wyraźnego sposobu oznaczenia metody jako „czystej wirtualnej”, więc klasa nie jest tak naprawdę abstrakcyjna.
Python> = 2.6: Istnieją abstrakcyjne klasy podstawowe ( http://docs.python.org/library/abc.html ). I pozwalają określić metody, które muszą być zaimplementowane w podklasach. Nie podoba mi się składnia, ale funkcja jest dostępna. W większości przypadków prawdopodobnie lepiej jest pisać na kaczych stronach po stronie klienta.
źródło
W bardziej prosty sposób wyjaśnić: Interfejs przypomina rodzaj pustej mufinki. Jest to plik klasy z zestawem definicji metod, które nie mają kodu.
Klasa abstrakcyjna to to samo, ale nie wszystkie funkcje muszą być puste. Niektóre mogą mieć kod. Nie jest ściśle pusty.
Po co różnicować: Nie ma praktycznej różnicy w Pythonie, ale na poziomie planowania dużego projektu może być bardziej powszechne mówienie o interfejsach, ponieważ nie ma kodu. Zwłaszcza jeśli pracujesz z programistami Java, którzy są przyzwyczajeni do tego terminu.
źródło
Zasadniczo interfejsy są używane tylko w językach, które używają modelu klasy z pojedynczym dziedziczeniem. W tych językach z pojedynczym dziedzictwem interfejsy są zwykle używane, jeśli jakakolwiek klasa może użyć określonej metody lub zestawu metod. Również w tych językach z dziedziczeniem pojedynczym klasy abstrakcyjne mają albo zdefiniowane zmienne klas oprócz żadnej lub więcej metod, albo wykorzystują model pojedynczego dziedziczenia do ograniczenia zakresu klas, które mogłyby korzystać z zestawu metod.
Języki obsługujące model wielokrotnego dziedziczenia zwykle używają tylko klas lub abstrakcyjnych klas bazowych, a nie interfejsów. Ponieważ Python obsługuje wielokrotne dziedziczenie, nie używa interfejsów i chciałbyś użyć klas podstawowych lub abstrakcyjnych klas podstawowych.
http://docs.python.org/library/abc.html
źródło
Klasy abstrakcyjne to klasy zawierające jedną lub więcej metod abstrakcyjnych. Oprócz metod abstrakcyjnych klasy abstrakcyjne mogą mieć metody statyczne, klasy i instancji. Ale w przypadku interfejsu będzie miał tylko abstrakcyjne metody, a nie inne. Dlatego dziedziczenie klasy abstrakcyjnej nie jest obowiązkowe, ale obowiązkowe jest dziedziczenie interfejsu.
źródło
Dla kompletności powinniśmy wspomnieć o PEP3119, gdzie ABC zostało wprowadzone i porównane z interfejsami oraz oryginalny komentarz Talina .
Klasa abstrakcyjna nie jest doskonałym interfejsem:
Ale jeśli pomyślisz o napisaniu go po swojemu:
dość szybko zdasz sobie sprawę, że wymyślasz koło, by ostatecznie osiągnąć
abc.ABCMeta
abc.ABCMeta
został zaproponowany jako użyteczny dodatek do brakującej funkcjonalności interfejsu, co jest dość sprawiedliwe w języku takim jak python.Z pewnością można go było ulepszyć podczas pisania wersji 3 oraz dodając nową składnię i niezmienną koncepcję interfejsu ...
Wniosek:
źródło