Ich möchte die abstrakte Klasse (ABCmeta) von Python im Detail erklären

0. Einleitung

Weil die abstrakte Klasse von Python unerwartet speziell war Ich möchte anhand der Erklärung der Metaklasse ein wenig sorgfältig erklären

1. Grundlegende Verwendung von ABCmeta

Pythons Abstract (abstrakte Klasse) ist etwas Besonderes, eine sogenannte Metaklasse Definieren Sie eine Klasse, indem Sie ABCmeta angeben (die Metaklasse wird später erläutert).

from abc import ABC, ABCMeta, abstractmethod

class Person(metaclass = ABCMeta):
    pass

Da es auch eine ABC-Klasse gibt, wird die Meta-Klasse übrigens nicht angegeben Grundsätzlich ist dies leichter zu verstehen, da es nur erbt

class Person(ABC):
    pass

Fügen Sie @abstractmethod zu der Methode hinzu, die Sie abstrahieren möchten

@abstractmethod
def greeting(self):
    pass

In geerbter Klasse implementieren

class Yamada(Person):

    def greeting(self):
        print("Hallo, das ist Yamada.")

Wenn Sie es nicht implementieren und instanziieren, tritt natürlich ein Fehler auf.

class Yamada(Person):
    pass

yamada = Yamada()
---------------------------------------------------------------------------------------------------------------
TypeError: Can't instantiate abstract class Yamada with abstract methods greeting

Im Folgenden wird beschrieben, wie die grundlegende abstrakte Klasse verwendet wird

1.1 Was ist überhaupt eine Metaklasse?

Ein bisschen abseits hier, über Metaklassen sprechen, überspringen, wenn Sie nicht interessiert sind

Was ist eine Metaklasse?

Bei der objektorientierten Programmierung ist eine Metaklasse eine Klasse, deren Instanz eine Klasse ist. So wie eine reguläre Klasse das Verhalten dieser Instanz definiert, definiert eine Metaklasse die Klasse, die diese Instanz ist, und das Verhalten einer Instanz dieser Klasse.

[Source]: Metaclass-wikipedia </ cite>

Ich bin mir nicht sicher, wenn Sie ein Beispiel geben Mit der versteckten Funktion (?) Von Python können Sie eine Klasse vom Typ dynamisch definieren.

def test_init(self):
    pass

Test_Class = type('Test_Class', (object, ), dict(__init__ = test_init, ))

Natürlich können Sie diese Klasse instanziieren

Test_Class_instance = Test_Class()
print(type(Test_Class_instance))
-------------------------------------------------------------------------------------------------------------------
<class '__main__.Test_Class'>

Die zu diesem Zeitpunkt vom Typ generierte Test_Class kann als Instanz oder Klassendefinition bezeichnet werden. Dies ist eine Metaklasse im engeren Sinne

Was überrascht, ist, dass die Klassen, die normalerweise in Python beiläufig definiert werden Es kann sich um eine Instanz vom Typ Typ handeln

class define_class:
    pass

print(type(define_class))
-------------------------------------------------------------------------------------------------------------------
<class 'type'>

Schließlich definiert Python eine Klasse intern type ('classname', ...) </ code> wird automatisch aufgerufen. Es stellt sich heraus, dass

Ändern Sie die Klasse, die automatisch aufgerufen werden kann Eine super mächtige Funktion ist die Identität von \ _ \ _ Metaklasse \ _ \ _, ABCmeta ist eine Klasse, die den Typ erbt ABC-Meta-Quellcode

Die Metaklasse ist übrigens zu leistungsfähig und ändert die Sprachspezifikation selbst. Es ist schwarze Magie, also solltest du sie nicht missbrauchen.

2. Abstraktion von Klassenmethode, statischer Methode und Eigenschaft

@abstractclassmethod、@abstractstaticmethod、@abstractproperty Beide sind veraltet, daher müssen Dekorateure gestapelt werden

Abstrakte Klasse

class Person(ABC):

    @staticmethod
    @abstractmethod
    def age_fudging(age):
        pass

    @classmethod
    @abstractmethod
    def weight_fudging(cls, weight):
        pass

    @property
    @abstractmethod
    def age(self):
        pass

    @age.setter
    @abstractmethod
    def age(self, val):
        pass

    @property
    @abstractmethod
    def weight(self):
        pass

    @weight.setter
    @abstractmethod
    def weight(self, val):
        pass

Implementierung

class Yamada(Person):

    def __init__(self):
        self.__age = 30
        self.__weight = 120
    
    #10-jährige Makrelenlesung
    @staticmethod
    def age_fudging(age):
        return age - 10
    
    #20 kg Makrelenlesung
    @classmethod
    def weight_fudging(cls, weight):
        return weight - 20
    
    @property
    def age(self):
        return Yamada.age_fudging(self.__age)
    
    @age.setter
    def age(self):
        return
    
    @property
    def weight(self):
        return self.weight_fudging(self.__weight)
    
    @weight.setter
    def weight(self):
        return

y = Yamada()
print("Name:Yamada Alter:{0}Körpergewicht:{1}".format(y.age, y.weight))
-----------------------------------------------------------------------------------------------------------------
Name:Yamada Alter:20 Gewicht:100

Es ist etwas länger her, aber die grundlegende Verwendung ist die gleiche Beachten Sie jedoch, dass eine Fehlermeldung angezeigt wird, wenn Sie unten nicht @abstractmethod erstellen.

In Python können Sie es übrigens privat machen, indem Sie der Mitgliedsvariablen "__" voranstellen.

3. Mehrfachvererbung abstrakter Klassen

Mehrfachvererbung ist in Python verfügbar, aber was ist mit abstrakten Klassen?

Wie Sie wissen, hat die Mehrfachvererbung verschiedene Probleme (Diamantvererbungsproblem, Namenskonflikt). Grundsätzlich ist es sicherer, keine Mehrfachvererbung zu verwenden. In diesem Fall muss es sich jedoch um eine Mixin-Klasse handeln.

3.1 Was ist Mixin?

mixin ist eine objektorientierte Programmiersprache Es ist eine Klasse, die Funktionen bereitstellt, indem sie von Unterklassen geerbt wird, und nicht dazu gedacht ist, unabhängig zu arbeiten. Abhängig von der Sprache Möglicherweise gibt es ein Mixin als separates System von dem, was die Sprache Klassen und Vererbung nennt (detailliert im Abschnitt #Variations).

[Source]: Mixin --wikipedia </ cite>

Auch aus Wikipedia zitiert, aber kurz gesagt Eine Klasse, die nur dann richtig funktioniert, wenn sie geerbt wurde </ b> Abstrakte Klassen und Schnittstellen sind ebenfalls Mixin-Klassen

Also werden wir eine Beastman-Klasse schaffen, die Katzen und Menschen erbt

class Cat(ABC):

    @abstractmethod
    def mew(self):
        pass
    
    #Auch persönlich
    @abstractmethod
    def sleep(self):
        pass

class Person(ABC):

    @abstractmethod
    def greeting(self):
        pass

    #Auch in Cat
    @abstractmethod
    def sleep(self):
        pass

class Therianthrope(Person, Cat):

    def greeting(self):
        print("Hallo")

    def mew(self):
        print("Miau")
    
    def sleep(self):
        print("zzz…")

cat_human = Therianthrope()

cat_human.greeting()
cat_human.mew()
cat_human.sleep()
-----------------------------------------------------------------------------------------------------------------
Hallo
Miau
zzz…

Sie können sehen, dass es auch mit ABC-Meta problemlos funktioniert Dieses Mal wird der Name der Methode mit dem Namen sleep zusammengestoßen. Es gibt kein Problem, da es nicht in der Vererbungsquelle implementiert ist

Schließlich, wie auf der offiziellen Python-Website geschrieben Sie sollten bei Kollisionen zwischen Metaklassen vorsichtig sein

4. Mehrstufige Vererbung abstrakter Klassen

Bei der mehrstufigen Vererbung geht es darum, ob ABCmeta bei der Vererbung erbt Mit anderen Worten, wenn Python eine abstrakte Klasse erbt, wird sie zu einer abstrakten Klasse. Der Punkt des Werdens

Zusammenfassend erbt ABCmeta, und wenn Sie eine abstrakte Klasse erben, wird sie zu einer abstrakten Klasse.

class Animal(metaclass=ABCMeta):
    pass

class Person(Animal):
    pass

class Yamada(Person):
    pass

print(type(Person))
print(type(Yamada))
-------------------------------------------------------------------------------------------------------------------
<class 'abc.ABCMeta'>
<class 'abc.ABCMeta'>

Wo ist denn die abstrakte Methode? Es bedeutet, dass es implementiert werden sollte

class Animal(metaclass=ABCMeta):

    @abstractmethod
    def run(self):
        pass


class Person(Animal):
    pass

class Yamada(Person):

    def run(self):
        print("12 km / h")

y = Yamada()
y.run()
-------------------------------------------------------------------------------------------------------------------
12 km / h

5. Nehmen Sie eine abstrakte Klasse als formales Argument

Es ist lange her, aber am Ende ist es eine grobe Skizze der abstrakten Klasse Einführung in ein Anwendungsbeispiel, das auch in Python verwendet werden kann

Selbst in Python können Sie den Typ des formalen Arguments und den Rückgabewert angeben. Ich habe "Person", die zuvor erstellte übergeordnete Klasse und abstrakte Klasse, als formalen Argumenttyp angegeben. Erstellen wir eine Funktion namens fall_asleep

from abstract import Person
import time

def fall_asleep(p:Person):
    sleep_time = p.sleep()
    time.sleep(sleep_time)
    print("!")
class Person(ABC):

    @abstractmethod
    def greeting(self):
        pass

    @abstractmethod
    def sleep(self) -> float:
        pass

Mit abstrakten Klassen und Typisierung ist es nicht mehr Python. Diese Art von Technik wird beim Erstellen einer etwas größeren Software in Python verwendet. Es ist nützlich für etwas.

Zum Beispiel kann die Person, die fall_asleep macht, den tatsächlichen Zustand der konkreten Klasse sehen (Yamada, Ikeda, Yosida). Mach dir keine Sorgen (weiß nicht), egal wie sehr du dich änderst, solange die Funktion Schlaf die Anforderungen erfüllt Da es abgeschlossen werden kann, kann gesagt werden, dass fall_asleep eher von der abstrakten Klasse (Person) als von der konkreten Klasse abhängt.

Dies nennt die Architektur das "Dependency Reversal Principle (DIP)". Sagen

Die folgenden Punkte gelten für DIP

  • Beziehen Sie sich nicht auf (variable) konkrete Klassen
  • Erben Sie keine (variablen) konkreten Klassen
  • Überschreiben Sie keine konkreten Funktionen

Schließlich ist es besser, sich auf abstrakte Klassen zu verlassen Sie können eine robuste Architektur erreichen.

y = Yamada()
fall_asleep(y)
-------------------------------------------------------------------------------------------------------------------
zzz…
!

Recommended Posts