Heim > Artikel > Backend-Entwicklung > Definieren und Verwenden abstrakter Klassen in Python
Jeder ist mit abstrakten Klassen in Java vertraut. Wir können das ABC-Modul verwenden, um abstrakte Klassen in Python zu erstellen.
Python ist wie Java kann auch eine abstrakte Klasse definieren.
Bevor wir über abstrakte Klassen sprechen, sprechen wir über die Implementierung abstrakter Methoden.
Abstrakte Methoden sind in der Basisklasse definierte Methoden, jedoch ohne Implementierung. In Java können Sie eine Methode als Schnittstelle deklarieren. Der einfache Weg, eine abstrakte Methode in Python zu implementieren, ist:
class Sheep(object): def get_size(self): raise NotImplementedError
Jede von Sheep geerbte Unterklasse muss die Methode get_size implementieren. Andernfalls wird ein Fehler generiert. Diese Implementierungsmethode hat jedoch einen Nachteil. Die definierte Unterklasse gibt nur dann einen Fehler aus, wenn diese Methode aufgerufen wird. Hier ist eine einfache Möglichkeit, es auszulösen, nachdem die Klasse instanziiert wurde. Verwenden Sie das von Python bereitgestellte abc-Modul.
import abc class Sheep(object): __metaclass__ = abc.ABCMeta @abc.absractmethod def get_size(self): return
Eine Ausnahme wird ausgelöst, wenn die Sheep-Klasse oder eine davon geerbte Unterklasse instanziiert wird (get_size ist nicht implementiert).
Somit können Sie durch die Definition einer abstrakten Klasse gemeinsame Methoden für Unterklassen definieren (und so deren Implementierung erzwingen).
So verwenden Sie abstrakte Klassen
import abc class A(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def load(self, input): return @abc.abstractmethod def save(self, output, data): return
Erstellen Sie eine abstrakte Klasse über die ABCMeta-Metaklasse und dekorieren Sie sie mit abstractmethod Container zur Angabe einer abstrakten Methode
Eine konkrete Klasse registrieren
class B(object): def load(self, input): return input.read() def save(self, output, data): return output.write(data) A.register(B) if __name__ == '__main__': print issubclass(B, A) # print True print isinstance(B(), A) # print True
Eine konkrete Klasse aus einer registrieren abstrakte Klasse
Unterklassenimplementierung
class C(A): def load(self, input): return input.read() def save(self, output, data): return output.write(data) if __name__ == '__main__': print issubclass(C, A) # print True print isinstance(C(), A) # print True
Sie können die Methode der Vererbung der abstrakten Klasse verwenden, um die zu implementieren Konkrete Klasse. Dies kann die Verwendung von Registern vermeiden. Der Nebeneffekt ist jedoch, dass Sie alle konkreten Klassen über die Basisklasse finden können
for sc in A.__subclasses__(): print sc.__name__ # print C
Wenn Sie Vererbung verwenden , finden Sie alle konkreten Klassen. Wenn Sie „register“ verwenden, wird es nicht gefunden.
Verwenden Sie __subclasshook__
Nach der Verwendung von __subclasshook__, solange die konkrete Klasse die definiert Dieselbe Methode wie die abstrakte Klasse, sie wird berücksichtigt Ist seine Unterklasse
import abc class A(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def say(self): return 'say yeah' @classmethod def __subclasshook__(cls, C): if cls is A: if any("say" in B.__dict__ for B in C.__mro__): return True return NotTmplementd class B(object): def say(self): return 'hello' print issubclass(B, A) # True print isinstance(B(), A) # True print B.__dict__ # {'say': <function say at 0x7f...>, ...} print A.__subclasshook__(B) # True
Unvollständige Implementierung
class D(A): def save(self, output, data): return output.write(data) if __name__ == '__main__': print issubclass(D, A) # print True print isinstance(D(), A) # raise TypeError
Wenn Sie eine unvollständige konkrete Klasse erstellen, wird D ausgegeben. Abstrakte Klassen und abstrakte Methoden können nicht instanziiert werden
Abstrakte Basisklassen in konkreten Klassen verwenden
import abc from cStringIO import StringIO class A(object): __metaclass__ = abc.ABCMeta @abc.abstractmethod def retrieve_values(self, input): pirnt 'base class reading data' return input.read() class B(A): def retrieve_values(self, input): base_data = super(B, self).retrieve_values(input) print 'subclass sorting data' response = sorted(base_data.splitlines()) return response input = StringIO("""line one line two line three """) reader = B() print reader.retrieve_values(input)
Ergebnisse drucken
base class reading data subclass sorting data ['line one', 'line two', 'line three']
Sie können super verwenden, um die Logik wiederzuverwenden in der abstrakten Basisklasse, aber es wird die untergeordnete Klasse zwingen, überschreibende Methoden bereitzustellen
import abc class A(object): __metaclass__ = abc.ABCMeta @abc.abstractproperty def value(self): return 'should never get here.' class B(A): @property def value(self): return 'concrete property.' try: a = A() print 'A.value', a.value except Exception, err: print 'Error: ', str(err) b = B() print 'B.value', b.valueDrucken Sie das Ergebnis aus. A kann nicht instanziiert werden, da es nur eine Getter-Methode für abstrakte Eigenschaften gibt.
Error: ... print concrete property
Abstraktes Lesen und Schreiben definieren Eigenschaften
import abc class A(object): __metaclass__ = abc.ABCMeta def value_getter(self): return 'Should never see this.' def value_setter(self, value): return value = abc.abstractproperty(value_getter, value_setter) class B(A): @abc.abstractproperty def value(self): return 'read-only' class C(A): _value = 'default value' def value_getter(self): return self._value def value_setter(self, value): self._value = value value = property(value_getter, value_setter) try: a = A() print a.value except Exception, err: print str(err) try: b = B() print b.value except Exception, err: print str(err) c = C() print c.value c.value = 'hello' print c.valueWenn Sie die Eigenschaft der konkreten Klasse definieren, muss sie mit der abstrakten Eigenschaft identisch sein. Es funktioniert nicht, wenn Sie nur eine davon überschreiben.
error: ... error: ... print 'default value' print 'hello'Verwenden Sie die Decorator-Syntax, um abstrakte Eigenschaften zum Lesen und Schreiben zu implementieren Das Schreiben sollte dasselbe sein.
import abc class A(object): __metaclass__ = abc.ABCMeta @abc.abstractproperty def value(self): return 'should never see this.' @value.setter def value(self, _value): return class B(A): _value = 'default' @property def value(self): return self._value @value.setter def value(self, _value): self._value = _value b = B() print b.value # print 'default' b.value = 'hello' print b.value # print 'hello'