it-swarm.com.de

Unterschied zwischen abstrakter Klasse und Schnittstelle in Python

Was ist der Unterschied zwischen abstrakter Klasse und Schnittstelle in Python?

516
gizmo

Was Sie manchmal sehen werden, ist das Folgende:

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" )

Da Python keinen formalen Schnittstellenvertrag hat (und nicht benötigt), existiert die Unterscheidung zwischen Abstraktion und Schnittstelle im Java-Stil nicht. Wenn sich jemand bemüht, eine formale Schnittstelle zu definieren, handelt es sich auch um eine abstrakte Klasse. Die einzigen Unterschiede bestünden in der angegebenen Absicht in der Doku-Zeichenfolge.

Und der Unterschied zwischen abstrakt und Benutzeroberfläche ist eine haarsträubende Sache, wenn Sie Enten tippen.

Java verwendet Schnittstellen, weil es keine Mehrfachvererbung hat.

Da Python mehrfach vererbt wird, wird möglicherweise auch so etwas angezeigt

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

Hierbei wird eine Art abstrakte Superklasse mit Mixins verwendet, um konkrete, nicht zusammenhängende Unterklassen zu erstellen.

578
S.Lott

Was ist der Unterschied zwischen abstrakter Klasse und Schnittstelle in Python?

Eine Schnittstelle für ein Objekt besteht aus einer Reihe von Methoden und Attributen für dieses Objekt.

In Python können wir eine abstrakte Basisklasse verwenden, um eine Schnittstelle zu definieren und zu erzwingen.

Verwenden einer abstrakten Basisklasse

Angenommen, wir möchten eine der abstrakten Basisklassen aus dem Modul collections verwenden:

import collections
class MySet(collections.Set):
    pass

Wenn wir versuchen, es zu verwenden, erhalten wir ein TypeError, da die von uns erstellte Klasse das erwartete Verhalten von Mengen nicht unterstützt:

>>> MySet()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MySet with abstract methods
__contains__, __iter__, __len__

Wir müssen also mindestens __contains__, __iter__ und __len__ implementieren. Verwenden wir dieses Implementierungsbeispiel aus der Dokumentation :

class ListBasedSet(collections.Set):
    """Alternate set implementation favoring space over speed
    and not requiring the set elements to be hashable. 
    """
    def __init__(self, iterable):
        self.elements = lst = []
        for value in iterable:
            if value not in lst:
                lst.append(value)
    def __iter__(self):
        return iter(self.elements)
    def __contains__(self, value):
        return value in self.elements
    def __len__(self):
        return len(self.elements)

s1 = ListBasedSet('abcdef')
s2 = ListBasedSet('defghi')
overlap = s1 & s2

Implementierung: Erstellen einer abstrakten Basisklasse

Wir können unsere eigene abstrakte Basisklasse erstellen, indem wir die Metaklasse auf abc.ABCMeta setzen und den Dekorator abc.abstractmethod für relevante Methoden verwenden. Die Metaklasse fügt die dekorierten Funktionen zum Attribut __abstractmethods__ hinzu und verhindert die Instanziierung, bis diese definiert sind.

import abc

Beispielsweise wird "effektiv" als etwas definiert, das in Worten ausgedrückt werden kann. Angenommen, wir wollten eine abstrakte Basisklasse definieren, die effektiv ist, in Python 2:

class Effable(object):
    __metaclass__ = abc.ABCMeta
    @abc.abstractmethod
    def __str__(self):
        raise NotImplementedError('users must define __str__ to use this base class')

Oder in Python 3 mit der geringfügigen Änderung der Metaklassendeklaration:

class Effable(object, metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def __str__(self):
        raise NotImplementedError('users must define __str__ to use this base class')

Wenn wir nun versuchen, ein effektives Objekt zu erstellen, ohne die Schnittstelle zu implementieren:

class MyEffable(Effable): 
    pass

und versuche es zu instanziieren:

>>> MyEffable()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class MyEffable with abstract methods __str__

Uns wird gesagt, dass wir den Job noch nicht beendet haben.

Wenn wir nun die erwartete Schnittstelle bereitstellen, gehen Sie wie folgt vor:

class MyEffable(Effable): 
    def __str__(self):
        return 'expressable!'

wir können dann die konkrete Version der Klasse verwenden, die von der abstrakten abgeleitet ist:

>>> me = MyEffable()
>>> print(me)
expressable!

Es gibt andere Dinge, die wir damit tun könnten, wie das Registrieren virtueller Unterklassen, die diese Schnittstellen bereits implementieren, aber ich denke, das würde den Rahmen dieser Frage sprengen. Die anderen hier vorgestellten Methoden müssten diese Methode jedoch mit dem Modul abc anpassen.

Fazit

Wir haben gezeigt, dass die Erstellung einer abstrakten Basisklasse Schnittstellen für benutzerdefinierte Objekte in Python definiert.

174
Aaron Hall

Python> = 2.6 hat abstrakte Basisklassen .

Abstrakte Basisklassen (abgekürzt ABCs) ergänzen das Duck-Typing, indem sie eine Möglichkeit bieten, Schnittstellen zu definieren, wenn andere Techniken wie hasattr () ungeschickt wären. Python enthält viele integrierte ABCs für Datenstrukturen (im Modul "Collections"), Zahlen (im Modul "Numbers") und Streams (im Modul "Io"). Mit dem abc-Modul können Sie Ihr eigenes ABC erstellen.

Es gibt auch das Zope Interface Modul, das von Projekten außerhalb von Zope wie Twisted verwendet wird. Ich kenne mich damit nicht wirklich aus, aber es gibt eine Wiki-Seite hier die vielleicht hilft.

Im Allgemeinen benötigen Sie das Konzept abstrakter Klassen oder Interfaces in python nicht (bearbeitet - Einzelheiten finden Sie in der Antwort von S.Lott).

100
JimB

Python hat keines der beiden Konzepte.

Es benutzt Duck Typing, wodurch Schnittstellen überflüssig wurden (zumindest für den Computer :-))

Python <= 2.5: Basisklassen existieren offensichtlich, aber es gibt keine explizite Möglichkeit, eine Methode als "rein virtuell" zu markieren, sodass die Klasse nicht wirklich abstrakt ist.

Python> = 2.6: Abstrakte Basisklassen do exist ( http://docs.python.org/library/abc.html ). Außerdem können Sie Methoden angeben, die in Unterklassen implementiert werden müssen. Die Syntax gefällt mir nicht besonders, aber die Funktion ist vorhanden. In den meisten Fällen ist es wahrscheinlich besser, auf der Client-Seite "using" die Enten-Eingabe zu verwenden.

38
Douglas Leeder

Einfacher ausgedrückt: Eine Benutzeroberfläche ähnelt einer leeren Muffinform. Es ist eine Klassendatei mit einer Reihe von Methodendefinitionen, die keinen Code enthalten.

Eine abstrakte Klasse ist dasselbe, aber nicht alle Funktionen müssen leer sein. Einige können Code haben. Es ist nicht unbedingt leer.

Warum unterscheiden: In Python gibt es keinen großen praktischen Unterschied, aber auf der Planungsebene für ein großes Projekt könnte es üblicher sein, über Schnittstellen zu sprechen, da es keinen Code gibt. Vor allem, wenn Sie mit Java Programmierern arbeiten, die an den Begriff gewöhnt sind.

29
SilentSteel

Im Allgemeinen werden Schnittstellen nur in Sprachen verwendet, die das Einfachvererbungsklassenmodell verwenden. In diesen Sprachen mit einfacher Vererbung werden Schnittstellen normalerweise verwendet, wenn eine Klasse eine bestimmte Methode oder einen Methodensatz verwenden kann. Auch in diesen Sprachen mit einfacher Vererbung werden abstrakte Klassen verwendet, um entweder zusätzlich zu keiner oder mehreren Methoden Klassenvariablen zu definieren oder um das Modell mit einfacher Vererbung zu nutzen, um den Klassenbereich zu begrenzen, der eine Reihe von Methoden verwenden kann.

Sprachen, die das Mehrfachvererbungsmodell unterstützen, verwenden in der Regel nur Klassen oder abstrakte Basisklassen und keine Schnittstellen. Da Python Mehrfachvererbung unterstützt, werden keine Schnittstellen verwendet, und Sie möchten Basisklassen oder abstrakte Basisklassen verwenden.

http://docs.python.org/library/abc.html

15
Lara Dougan

Abstrakte Klassen sind Klassen, die eine oder mehrere abstrakte Methoden enthalten. Abstrakte Klassen können neben abstrakten Methoden auch statische Methoden, Klassen- und Instanzmethoden haben. Aber im Falle einer Schnittstelle wird es nur abstrakte Methoden geben, keine anderen. Daher ist es nicht obligatorisch, abstrakte Klassen zu erben, aber es ist obligatorisch, Schnittstellen zu erben.

0
Akash Ukarande