Weil die abstrakte Klasse von Python unerwartet speziell war Ich möchte anhand der Erklärung der Metaklasse ein wenig sorgfältig erklären
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
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.
@abstractclassmethod、@abstractstaticmethod、@abstractproperty Beide sind veraltet, daher müssen Dekorateure gestapelt werden
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
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.
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.
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
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
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
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