[Python] Was wird durch Mehrfachvererbung geerbt?

Über diesen Artikel

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.

Was ist Vererbung?

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 **.

Vererbungsreihenfolge

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 es Ihnen sagen

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.

Was ist Mehrfachvererbung?

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? ..

Reihenfolge der Mehrfachvererbung

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.

MRO wird es Ihnen sagen

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 '>)".

Vorsichtsmaßnahmen für __init__ beim mehrfachen Erben

Wenn 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

Ich habe versucht, mit Mehrfachvererbung zu spielen

Es ist ein bisschen lang von hier. Ich bin selbstzufrieden.

Aufbau

** 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

Klasse definieren

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! )')

Spiele in der definierten Klasse

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! )

Geburt eines halben Elfen

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!')

Untersuchen Sie MRO


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.

Untersuchen Sie die Attribute

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.

Untersuchen Sie die Methode

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.

Warum wird "Saugkraft" nicht ü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) keinesuction_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!
'''

Versuche zu spielen

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

[Python] Was wird durch Mehrfachvererbung geerbt?
Was ist Python?
Was ist Python?
[Python] Was ist Pipeline ...
[Python] Was ist virtualenv?
[Python] Python und Sicherheit - is Was ist Python?
[Python] * args ** Was ist kwrgs?
Python-Grundkurs (1 Was ist Python?)
[Python] Was ist eine Zip-Funktion?
[Python] Was ist eine with-Anweisung?
[Python] Sortierbar nach mehreren Bedingungen sortieren
[Python] Was ist @? (Über Dekorateure)
[Python] Was ist der sortierte Schlüssel?
Python für Anweisung ~ Was ist iterierbar ~
Wofür ist der Python-Unterstrich (_)?
Python> Was ist ein erweitertes Slice?
Mehrfachvererbung
Erklären Sie die stochastische Gradientenabstiegsmethode, indem Sie sie in Python ausführen
Python # Vererbung (Vererbung)
[Python] Was ist Pandas Series und DataFrame?
Was ist NaN? NaN Zoya (Python) (394 Tage zu spät)
Was für eine Programmiersprache ist Python?
Was ist "Mahjong" in der Python-Bibliothek? ??
Was ist ein Hund? Python-Installationsvolumen
Blender 2.9, Python, Wählen Sie mehrere Netze nach Koordinaten aus
Was ist ein Namespace?
Was ist ein Algorithmus? Einführung in den Suchalgorithmus] ~ Python ~
Warum Python Slicing durch einen Doppelpunkt (:) dargestellt wird
Was ist copy.copy ()
Was ist "funktionale Programmierung" und "objektorientiert"? Python Edition
Python ist einfach
Was ist Django? .. ..
Was ist dotenv?
Was ist POSIX?
Was ist im Docker Python-Image pfeifend?
Was ist Linux?
Was ist klass?
Ich habe Python ausprobiert! ] Heute Abschluss von "Jeder Python! Was ist Python!"!
Was ist SALOME?
Informationen zur Python-Vererbung
[Python] Ravel () ist praktisch, wenn Sie mehrere Diagramme zeichnen
Was ist Linux?
Was vergleichst du mit Python und ==?
Was ist Hyperopt?
Python ist eine Instanz
Was ist Linux?
[Einführung in die Udemy Python3 + -Anwendung] 54. Was ist Docstrings?
Ändern Sie, was von einer von Dango autorisierten Person angezeigt wird
Was ist Pyvenv?
Was ist __call__?
Was ist Linux?
Sag mir, was eine gleichwinklige Abbildung ist, Python!
Was ist der [Ruby / Python / Java / Swift / JS] -Algorithmus?
[Python] Kalender Heatmap [Plotly] Memo
[Statistik] Verstehen Sie anhand von Animationen, wie die ROC-Kurve aussieht.
Python3 datetime ist schneller, wenn nur die Zeitzone angegeben wird
Was ist Gott? Erstelle einen einfachen Chatbot mit Python