Suche…


Einstellen der ABCMeta-Metaklasse

Abstrakte Klassen sind Klassen, die vererbt werden sollen, vermeiden jedoch die Implementierung bestimmter Methoden und hinterlassen nur Methodensignaturen, die von Unterklassen implementiert werden müssen.

Abstrakte Klassen sind nützlich, um Klassenabstraktionen auf hoher Ebene zu definieren und durchzusetzen, ähnlich dem Konzept von Schnittstellen in typisierten Sprachen, ohne dass eine Methodenimplementierung erforderlich ist.

Ein konzeptioneller Ansatz zum Definieren einer abstrakten Klasse besteht darin, die Klassenmethoden auszulagern und dann einen NotImplementedError auszulösen, wenn darauf zugegriffen wird. Dadurch wird verhindert, dass untergeordnete Klassen auf übergeordnete Methoden zugreifen, ohne sie vorher zu überschreiben. So wie:

class Fruit:
    
    def check_ripeness(self):
        raise NotImplementedError("check_ripeness method not implemented!")


class Apple(Fruit):
    pass


a = Apple()
a.check_ripeness() # raises NotImplementedError

Das Erstellen einer abstrakten Klasse auf diese Weise verhindert die unzulässige Verwendung von Methoden, die nicht überschrieben werden, und ermutigt sicherlich dazu, Methoden in untergeordneten Klassen zu definieren, erzwingen jedoch keine Definition. Mit dem Modul abc können wir verhindern, dass untergeordnete Klassen instanziiert werden, wenn sie die abstrakten Klassenmethoden ihrer Eltern und Vorfahren nicht überschreiben:

from abc import ABCMeta

class AbstractClass(object):
    # the metaclass attribute must always be set as a class variable 
    __metaclass__ = ABCMeta

   # the abstractmethod decorator registers this method as undefined
   @abstractmethod 
   def virtual_method_subclasses_must_define(self):
       # Can be left completely blank, or a base implementation can be provided
       # Note that ordinarily a blank interpretation implicitly returns `None`, 
       # but by registering, this behaviour is no longer enforced.

Es ist jetzt möglich, die Unterklasse einfach zu überschreiben und zu überschreiben:

class Subclass(AbstractClass):
    def virtual_method_subclasses_must_define(self):
        return

Warum / Wie werden ABCMeta und @abstractmethod verwendet?

Abstrakte Basisklassen (ABCs) erzwingen, welche abgeleiteten Klassen bestimmte Methoden der Basisklasse implementieren.

Um zu verstehen, wie das funktioniert und warum wir es verwenden sollten, betrachten wir ein Beispiel, das Van Rossum gefallen würde. Nehmen wir an, wir haben eine Basisklasse "MontyPython" mit zwei Methoden (joke & punchline), die von allen abgeleiteten Klassen implementiert werden müssen.

class MontyPython:
    def joke(self):
        raise NotImplementedError()

    def punchline(self):
        raise NotImplementedError()

class ArgumentClinic(MontyPython):
    def joke(self):
        return "Hahahahahah"

Wenn wir ein Objekt instanziieren und zwei Methoden aufrufen, erhalten wir (wie erwartet) einen Fehler mit der punchline() -Methode.

 >>> sketch = ArgumentClinic() 
 >>> sketch.punchline() 
NotImplementedError 

Dies ermöglicht es uns jedoch immer noch, ein Objekt der ArgumentClinic-Klasse zu instanziieren, ohne einen Fehler zu erhalten. Tatsächlich erhalten wir keine Fehlermeldung, bis wir die Punchline () suchen.

Dies wird durch die Verwendung des ABC-Moduls (Abstract Base Class) vermieden. Mal sehen, wie das mit demselben Beispiel funktioniert:

from abc import ABCMeta, abstractmethod

class MontyPython(metaclass=ABCMeta):
    @abstractmethod
    def joke(self):
        pass

@abstractmethod
def punchline(self):
    pass

class ArgumentClinic(MontyPython):
    def joke(self):
        return "Hahahahahah"

Wenn wir dieses Mal versuchen, ein Objekt aus der unvollständigen Klasse zu instanziieren, erhalten wir sofort einen TypeError!

>>> c = ArgumentClinic()
TypeError:
"Can't instantiate abstract class ArgumentClinic with abstract methods punchline"

In diesem Fall ist es einfach, die Klasse abzuschließen, um alle TypeErrors zu vermeiden:

class ArgumentClinic(MontyPython):
    def joke(self):
        return "Hahahahahah"

    def punchline(self):
        return "Send in the constable!"

Dieses Mal, wenn Sie ein Objekt instanziieren, funktioniert es!



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow