Ich möchte Django überschreiben und seine Funktionalität ändern, aber ich weiß nicht, wie ich es machen soll ... Ich habe studiert, weil ich den Code für mehrere Gelenke überhaupt nicht lesen konnte. In diesem Artikel möchte ich den Mechanismus und die Verwendung der Mehrfachvererbung von Python organisieren und schließlich damit spielen.
Vererbung ist die Vererbung der Funktionalität einer Klasse.
#Basisklasse
class Coffee(object):
def __init__(self, color, fragrance, price, taste, elapsed_time):
self.color = color
self.fragrance = fragrance
self.price = price
self.satisfaction = ((taste + fragrance) * price) - elapsed_time
def drink(self):
print(f'Befriedigung{self.satisfaction}Trinken Sie Hoffy auf den Punkt')
coffee = Coffee('brown', 10, 200, 10, 300)
coffee.drink() # <---Trinken Sie Hoffy mit 3700 Zufriedenheitspunkten
#Erben (abgeleitete Klasse)
class Coffee2(Coffee):
pass # <-Hat genau die gleiche Funktion wie Kaffee
class Nihonsyu(Coffee2):
pass # <-Hat genau die gleiche Funktion wie Coffee2
Geerbte Klassen können Funktionen hinzufügen, indem sie Methoden hinzufügen oder überschreiben.
Das Erben einer Klasse wie class Coffee2 (Coffee):
heißt ** Einzelvererbung **.
Im Fall einer Einzelvererbung wie oben können Sie dies herausfinden, indem Sie einfach die Vererbungsquelle verfolgen.
Nihonsyu <- Coffee2 <- Coffee
Die Klassenvererbung sucht nach Methoden in der Vererbungsreihenfolge und erbt diese Methoden. Wenn mehrere übergeordnete Klassen denselben Methodennamen haben, kann übrigens nur die Methode der ersten geerbten übergeordneten Klasse geerbt werden. Wenn jedoch "super ()" in der Methode der übergeordneten Klasse definiert ist, können alle Funktionen der übergeordneten Klasse und der übergeordneten Klasse vererbt werden. In beiden Fällen müssen Sie verstehen, welche Methoden vererbt werden, wenn Sie mehrere Vererbungsmethoden überschreiben möchten. Dazu scheint es notwendig zu sein, die Reihenfolge der Vererbung der übergeordneten Klasse zu kennen.
MRO wird als "Method Resolution Order" bezeichnet. Dies ist die Reihenfolge, in der die Methoden beim Erben einer Klasse durchsucht werden.
Pythons Basisklasse object
hat eine Methode namens mro, mit der die MRO ermittelt werden kann. Versuchen wir es also mit dem obigen Code.
print(Nihonsyu.__mro__)
# (<class '__main__.Nihonsyu'>, <class '__main__.Coffee2'>, <class '__main__.Coffee'>, <class 'object'>)
Es wurde angezeigt als "(<class '__ main__. Nihonsyu'>, <class '__ main__. Coffee2'>, <class '__ main__. Coffee'>, <class'object '>)". Wie Sie sehen, konnte ich die Suchreihenfolge der Methoden anzeigen.
Mehrfachvererbung ist der Zustand, in dem zwei oder mehr Klassen als Argument der Klasse übergeben werden.
class A:
def hello(self):
print('Hello from A')
class B(A):
pass
class C(A):
def hello(self):
print('Hello from C')
class D(B, C): # <-Mehrfachvererbung
pass
D ist eine mehrfach vererbte Klasse. Was wird ausgegeben, wenn die Hallo-Methode für eine Instanz von D ausgeführt wird?
d = D()
d.hello()
# Hello from C
Hallo von C wird ausgegeben. Mit anderen Worten, es erbt die Methode der Klasse C. Da es sich um "Klasse D (B, C)" handelt, dachte ich, dass "Klasse B" priorisiert und das "Hallo von A" der Klasse A, das die gesamte Klasse B erbt, ausgegeben wird. Warum? ..
Es scheint, dass es "Tiefenpriorität" und "Breitenpriorität" als Algorithmen zum Bestimmen der Reihenfolge der Mehrfachvererbung gibt, aber Python scheint einen Algorithmus zu verwenden, der weder "linearer Typ C" ist. Ich werde dies weglassen, weil es eine tiefe Geschichte sein wird, aber es scheint, dass sich die MRO in Abhängigkeit von der Struktur der Mehrfachvererbung ändert und die Suche weniger redundant ist.
Zur Zeit können Sie die MRO mit __mro__
herausfinden, also lassen Sie es uns überprüfen.
Versuchen Sie es mit dem obigen Mehrfachvererbungscode.
print(D.__mro__)
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
Es wurde "(<class '__ main__. D'>, <class '__ main__. B'>, <class '__ main__. C'>, <class '__ main__. A'>, <class'object '>)".
__init__
beim mehrfachen ErbenWenn eine Mehrfachvererbung durchgeführt wird, werden Methoden usw. gemäß MRO vererbt, aber es scheint, dass Methoden mit demselben Namen nur diejenigen der ersten vererbten Klasse erben können. Es wäre schön, wenn eine Methode mit demselben Namen nicht existiert, aber da __init__
fast immer existiert, scheint es notwendig zu sein, init der Klasse, die Sie mit super () erben möchten, fest aufzurufen und den Initialisierungsprozess ordnungsgemäß durchzuführen. ..
Auch das "init" in der Code "-Klasse C" unten scheint das "init" der "Objektklasse" zu überschreiben, aber zum Zeitpunkt der Mehrfachvererbung folgen die Methoden der Reihenfolge "MRO". Es scheint __init__
von B
neben C
zu überschreiben, weil es zu überschreiben scheint.
** Denken Sie daran, dass sich die Reihenfolge der von super ()
überschriebenen Methoden während der Mehrfachvererbung ändert **
class B:
def __init__(self):
self.b_value = 'B'
print('class B init')
super().__init__()
class C:
def __init__(self):
self.c_value = 'C'
print('class C init')
super().__init__()
class D(C, B):
def __init__(self):
print('class D init')
super().__init__()
print(D.__mro__)
# (<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class 'object'>)
d = D()
d
#↑ class D init
# class C init
# class B init
Es ist ein bisschen lang von hier. Ich bin selbstzufrieden.
** Allen Rassen gemeinsam ** Attribute: "Name", "Leben", "Alter", "Mana", "Ausdauer" Methoden: "Angriff", "Magie", "Verteidigung", "Nieder"
** Rennspezifisch **
Mensch | Elf | |
---|---|---|
Attribut | luck(Glück) | suction_power(Saugkraft?) |
Methode 1 | sword_skill | bow_skill |
Methode 2 | life_up | drain |
Wir erben die Basisklasse "Race" (Rasse) und erstellen die Klassen "Human" und "Elf".
import random
class Race(object):
def __init__(self, name, age, life, mana, stamina):
self.name = name
self.age = age
self.life = life
self.mana = mana
self.stamina = stamina
def attack(self):
self.stamina -= 10
print(f'{self.name}Schlagen Sie das Monster!')
def magic(self):
self.mana -= 10
print(f'{self.name}Gefrorene Monster!')
def defence(self):
self.life -= 1
print(f'{self.name}Den Angriff verhindert!')
def down(self):
self.life -= 10
print(f'{self.name}Wurde angegriffen!')
class Human(Race):
def __init__(self, name, age, life, mana, stamina, luck):
super(Human, self).__init__(name, age, life, mana, stamina)
self.luck = luck
def sword_skill(self):
self.stamina -= 20
self.life += 10
print(f'{self.name}Schlachte ein Monster mit einer schnellen Schwertkunst!')
print(f'{self.name}Monster das Leben gestohlen!')
#Das Leben wird mit einem zufälligen Wert wiederhergestellt
def life_up(self):
self.life_incremental = self.life + random.randint(1, 5) * self.luck
self.life = self.life + self.life_incremental
print(f'Gott war auf der Seite! (({self.name}Leben{self.life_incremental}Ich habe mich erholt! )')
class Elf(Race):
def __init__(self, name, age, life, mana, stamina, suction_power):
super(Elf, self).__init__(name, age, life, mana, stamina)
self.suction_power = suction_power
def bow_skill(self):
self.stamina -= 20
self.mana += 10
print(f'{self.name}Ein Monster aus der Ferne geschlachtet!')
print(f'{self.name}Mana von einem Monster gesaugt!')
def drain(self):
self.mana_incremental = self.mana + random.randint(1, 5) * self.suction_power
self.mana = self.mana + self.mana_incremental
print(f'Gott war auf der Seite!{self.name}Mana{self.mana_incremental}Ich habe mich erholt! )')
kirito = Human('Kirito', 18, 300, 200, 200, 10)
kirito.attack()
kirito.magic()
kirito.defence()
kirito.down()
kirito.sword_skill()
kirito.life_up()
print('---' * 10)
shinon = Elf('Sinon', 18, 200, 300, 200, 15)
shinon.attack()
shinon.magic()
shinon.defence()
shinon.down()
shinon.bow_skill()
shinon.drain()
Ergebnis
Kirito hat das Monster getroffen!
Gefrorenes Kirito-Monster!
Kirito hat den Angriff verhindert!
Kirito wurde angegriffen!
Kirito schlachtete ein Monster mit einer schnellen Schwertkunst!
Kirito hat dem Monster das Leben geraubt!
Gott war auf der Seite! (Kiritos Leben hat sich 319 erholt!)
------------------------------
Shinon hat das Monster getroffen!
Gefrorenes Shinon-Monster!
Shinon-Angriff verhindert!
Ich habe einen Shinon-Angriff!
Shinon hat ein Monster aus der Ferne geschlachtet!
Shinon saugte Mana aus dem Monster!
Gott war auf der Seite! Shinon hat 375 Mana wiedererlangt! )
Erstellen Sie eine Klasse "HalfElf", die die Klasse "Human" und die Klasse "Elf" mehrmals erbt. ** Was ich tun möchte, ist eine Rasse zu erstellen: Halbelf, der alle rassenspezifischen Attribute und Methoden sowie die gemeinsamen Attribute und Methoden enthält **
Lassen Sie uns zuerst "Mensch" und "Elf" erben, ohne "init" zu berühren.
Berühren Sie nicht den Initialisierer
class HalfElf(Human, Elf):
def super_drain(self):
self.super_drain = (self.luck + self.suction_power) * random.randint(1, 5)
print(f'Gott war auf der Seite!{self.name}Mana von Monstern{self.super_drain}Ich habe es aufgesaugt!')
print(HalfElf.__mro__)
# (<class '__main__.HalfElf'>, <class '__main__.Human'>, <class '__main__.Elf'>, <class '__main__.Race'>, <class 'object'>)
Es scheint, dass Sie zuerst nach "Mensch" suchen. Bei der Mehrfachvererbung ändern sich die von "super (eigene Klasse, selbst)" aufgerufenen Klassen in der Reihenfolge der MRO, sodass "super () .__ init__" der "Human" -Klasse zu einem Parameter von "init" der "Elf" -Klasse wird. Versuche, seinen eigenen Wert zu übergeben. Die "Saugkraft", die in "Elf" existiert, ist jedoch nicht in "Mensch", und umgekehrt ist das "Glück", das in "Mensch" existiert, nicht in "Elf", so dass es nur einen Fehler auslöst.
Um dies zu lösen, müssen Sie im obigen Code "super ()" verwenden und den entsprechenden Klassennamen an das Argument "super ()" übergeben. Dazu später mehr.
Was sind die Attribute von HalfElf
?
asuna = HalfElf()
# TypeError: __init__() missing 6 required positional arguments: 'name', 'age', 'life', 'mana', 'stamina', and 'luck'
Die Attribute haben "Name", "Alter", "Leben", "Mana", "Ausdauer", "Glück". Hat keine "Saugkraft". Weil es das "init" des Menschen nennt.
print(dir(HalfElf))
# ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'attack', 'bow_skill', 'defence', 'down', 'drain', 'life_up', 'magic', 'super_drain', 'sword_skill']
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'attack', 'bow_skill', 'defence', 'down', 'drain', 'life_up', 'magic', 'super_drain', 'sword_skill'] Es wurde
.
Alles wurde übernommen.
Da der Initialisierer nicht beschrieben wird, entspricht er genau dem Initialisierer der menschlichen Klasse, nach dem zuerst in MRO gesucht wird, sodass "suction_power" nicht vererbt wird.
Darüber hinaus sollte "Human" für die Einzelvererbung "super" verwenden, um den Initialisierer der Basisklasse "Race" aufzurufen. Diesmal handelt es sich jedoch um eine Mehrfachvererbung, sodass "Elf" gemäß der Wurzel von MRO aufgerufen wird. .. Das Attribut "suction_power" existiert jedoch nicht in "Human". Daher wird zur Instanzzeit immer ein Fehler ausgegeben.
error
class HalfElf(Human, Elf):
def super_drain(self):
self.super_drain = (self.luck + self.suction_power) * random.randint(5, 10)
print(f'Gott war auf der Seite!{self.name}Mana von Monstern{self.super_drain}Ich habe es aufgesaugt!')
asuna = HalfElf('Asuna', 18, 200, 300, 200, 10, suction_power=10)
# TypeError: __init__() got an unexpected keyword argument 'suction_power'
#Absaugen auf menschliche Eigenschaften_Weil es keine Kraft gibt
asuna = HalfElf('Asuna', 18, 200, 300, 200, 10)
# TypeError: __init__() missing 1 required positional argument: 'suction_power'
#Es gibt eine Eigenschaft der Elfenklasse, die Sie aufrufen_Weil kein Wert an die Macht übergeben wurde
suna = HalfElf('Asuna', 18, 200, 300, 200, 10, 10)
# TypeError: __init__() takes 7 positional arguments but 8 were given
#Weil die menschliche Klasse insgesamt 7 Argumente hat
Ich denke, dass es nicht gut funktioniert, weil die in den beiden übergeordneten Klassen definierten Eigenschaften unterschiedlich sind und sich die Methodensuchroute für mehrere Vererbungen in der Reihenfolge der MRO ändert. (schwer....!!)
Um dies zu lösen, haben wir Folgendes getan:
super(HalfElf, self).__init__()
Ich nannte den Initialisierer der nächsten Klasse "Mensch" meiner Klasse.
In diesem Fall wird der Human-Klasseninitialisierer aufgerufen. Wenn Sie jedoch die Elf
-Klasse mit super
in der Human
-Klasse aufrufen, hat die Eigenschaft vonsuper (). __ init__ (in diesem Fall) keine
suction_power und stimmt nicht mit der Eigenschaft von
Elf` überein, sodass ein Fehler auftritt. Ich werde herauskommen.
(Vielleicht ... verstehe ich nicht klar ...)
error
class HalfElf(Human, Elf):
def __init__(self, name, age, life, mana, stamina, luck, suction_power):
super(HalfElf, self).__init__(name, age, life, mana, stamina, luck)
self.suction_power = suction_power
def super_drain(self):
self.super_drain = (self.luck + self.suction_power) * random.randint(5, 10)
print(f'Gott war auf der Seite!{self.name}Mana von Monstern{self.super_drain}Ich habe es aufgesaugt!')
asuna = HalfElf('Asuna', 18, 200, 300, 200, 10, 10)
'''
File "Main.py", line 85, in <module>
asuna = HalfElf('Asuna', 18, 200, 300, 200, 10, 10)
File "Main.py", line 75, in __init__
super(HalfElf, self).__init__(name, age, life, mana, stamina, luck)
File "Main.py", line 30, in __init__
super(Human, self).__init__(name, age, life, mana, stamina)
TypeError: __init__() missing 1 required positional argument: 'suction_power'
'''
super(Human, self).__init__()
Nannte den Initialisierer für die nächste Klasse "Elf" der menschlichen Klasse.
In Elf nennt "super" die "Race" -Klasse, aber die Eigenschaften der "Elf" -Klasse erfüllen die Eigenschaften der "Race" -Klasse, sodass kein Fehler auftritt. Stattdessen wurde das "Glück" der "menschlichen" Klasse überhaupt nicht übernommen, deshalb werde ich es wieder mit "self.luck = Glück" ergänzen.
Gut gearbeitet
class HalfElf(Human, Elf):
def __init__(self, name, age, life, mana, stamina, suction_power, luck):
super(Human, self).__init__(name, age, life, mana, stamina, suction_power)
self.luck = luck
def super_drain(self):
self.super_drain = (self.luck + self.suction_power) * random.randint(5, 10)
print(f'Gott war auf der Seite!{self.name}Mana von Monstern{self.super_drain}Ich habe es aufgesaugt!')
asuna = HalfElf('Asuna', 18, 200, 300, 200, 10, 10)
asuna.attack()
asuna.magic()
asuna.defence()
asuna.down()
asuna.sword_skill()
asuna.life_up()
asuna.bow_skill()
asuna.drain()
asuna.super_drain()
'''
Asuna hat das Monster getroffen!
Gefrorenes Asuna Monster!
Asuna-Angriff verhindert!
Ich habe einen Asuna-Angriff!
Asuna hat ein Monster mit einer schnellen Schwertkunst geschlachtet!
Asuna hat dem Monster das Leben geraubt!
Gott war auf der Seite! (Asunas Leben hat sich erholt!)
Ich habe ein Monster aus der Ferne geschlachtet!
Ich habe Mana von einem Monster gesaugt!
Gott war auf der Seite! Asuna hat 330 Mana zurückgewonnen! )
Gott war auf der Seite! Asuna hat dem Monster 200 Mana entzogen!
'''
Ich dachte, wenn ich "Mensch" und "Elf" erben würde, könnte ich leicht "Halbelf" erschaffen, aber das war überhaupt nicht der Fall und es war sehr schwierig. Das Umschreiben des Codes der Basisklasse zum Erstellen einer Mehrfachvererbung wirkt sich auf anderen Code aus. Daher möchte ich mehr darüber erfahren, wie eine Klasse geschrieben wird. Als nächstes möchte ich Mixin ausprobieren.
Recommended Posts