Je veux remplacer Django et changer ses fonctionnalités, mais je ne sais pas comment le faire ... J'ai étudié parce que je ne pouvais pas lire le code multi-joint en premier lieu. Dans cet article, j'aimerais organiser le mécanisme et l'utilisation de l'héritage multiple de Python, et enfin jouer avec.
L'héritage est l'héritage de la fonctionnalité d'une classe.
#Classe de base
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'la satisfaction{self.satisfaction}Boire Hoffy du point')
coffee = Coffee('brown', 10, 200, 10, 300)
coffee.drink() # <---Buvez Hoffy avec 3700 points de satisfaction
#Hériter (classe dérivée)
class Coffee2(Coffee):
pass # <-A exactement la même fonction que le café
class Nihonsyu(Coffee2):
pass # <-A exactement la même fonction que Coffee2
Les classes héritées peuvent ajouter des fonctionnalités en ajoutant ou en remplaçant des méthodes.
L'héritage d'une classe comme class Coffee2 (Coffee):
est appelé ** héritage unique **.
Dans le cas de l'héritage unique comme décrit ci-dessus, vous pouvez le découvrir en traçant simplement la source d'héritage.
Nihonsyu <- Coffee2 <- Coffee
L'héritage de classe recherche les méthodes dans l'ordre d'héritage et hérite de ces méthodes.
À propos, lorsque plusieurs classes parentes ont le même nom de méthode, seule la méthode de la première classe parente héritée peut être héritée.
Cependant, si super ()
est défini dans la méthode de la classe parente, toutes les fonctions de la classe parente et de la classe parente peuvent être héritées.
Dans tous les cas, si vous souhaitez remplacer plusieurs méthodes d'héritage, vous devez comprendre quelles méthodes sont héritées. Pour ce faire, il semble nécessaire de connaître l'ordre d'héritage de la classe parente.
MRO est appelé «Ordre de résolution des méthodes». Il s'agit de l'ordre dans lequel les méthodes sont recherchées lors de l'héritage d'une classe. La classe de base de Python ʻobject` a une méthode appelée mro, qui peut être utilisée pour connaître le MRO, alors essayons-la avec le code ci-dessus.
print(Nihonsyu.__mro__)
# (<class '__main__.Nihonsyu'>, <class '__main__.Coffee2'>, <class '__main__.Coffee'>, <class 'object'>)
Il était affiché sous la forme (<class '__ main__. Nihonsyu'>, <class '__ main__. Coffee2'>, <class '__ main__. Coffee'>, <class'object '>)
. Comme vous pouvez le voir, j'ai pu afficher l'ordre de recherche des méthodes.
L'héritage multiple est l'état lorsque deux classes ou plus sont passées comme argument de la classe.
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): # <-Héritage multiple
pass
D est une classe multi-héritée, que sera généré lors de l'exécution de la méthode hello sur une instance de D?
d = D()
d.hello()
# Hello from C
Bonjour de C est sorti. En d'autres termes, il hérite de la méthode de classe C
.
Puisqu'il s'agit de la «classe D (B, C)», je pensais que la «classe B» serait prioritaire et que le «Bonjour de A» de la classe A, qui hérite de toute la classe B, serait affiché. Pourquoi? ..
Il semble qu'il existe des algorithmes de «priorité de profondeur» et de «priorité de largeur» qui déterminent l'ordre d'héritage multiple, mais Python semble adopter un algorithme qui n'est ni de type «C linéaire». Je vais omettre cela car ce sera une histoire profonde, mais il semble que le MRO change en fonction de la structure de l'héritage multiple, et la recherche est moins redondante.
Pour le moment, vous pouvez trouver le MRO en utilisant __mro__
, alors vérifions-le.
Essayez-le avec le code d'héritage multiple ci-dessus.
print(D.__mro__)
# (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
Il est devenu (<class '__ main __. D'>, <class '__ main__. B'>, <class '__ main__. C'>, <class '__ main__. A'>, <class'object '>)
.
Lorsque l'héritage multiple est effectué, les méthodes, etc. sont héritées selon MRO, mais il semble que les méthodes portant le même nom ne peuvent hériter que de celles de la première classe héritée. Ce serait bien si une méthode avec le même nom n'existe pas, mais comme __init__
existe presque toujours, il semble qu'il soit nécessaire d'appeler fermement init de la classe dont vous voulez hériter avec super () et d'effectuer correctement le processus d'initialisation. ..
De plus, le «init» dans le code «classe C» ci-dessous semble remplacer le «init» de la «classe d'objet», mais au moment de l'héritage multiple, les méthodes suivent l'ordre de «MRO». Il semble remplacer «init» de «B» à côté de «C» car il semble écraser.
** N'oubliez pas que l'ordre des méthodes remplacées par super ()
change pendant l'héritage multiple **
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
C'est un peu long d'ici. Je suis satisfait de moi-même.
** Commun à toutes les races **
Attributs: nom
, vie
, ʻage,
mana,
endurance`
Méthodes: «attaque», «magie», «défense», «bas»
** Spécifique à la course **
Humain | Elfe | |
---|---|---|
attribut | luck(la chance) | suction_power(Puissance d'aspiration?) |
Méthode 1 | sword_skill | bow_skill |
Méthode 2 | life_up | drain |
En héritant de la classe de base Race
(race), nous créons les classes Human
et ʻ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}Frappez le monstre!')
def magic(self):
self.mana -= 10
print(f'{self.name}Monstres gelés!')
def defence(self):
self.life -= 1
print(f'{self.name}Empêché l'attaque!')
def down(self):
self.life -= 10
print(f'{self.name}A été attaqué!')
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}Vous avez massacré un monstre avec un savoir-faire rapide!')
print(f'{self.name}Volé la vie des monstres!')
#La vie est restaurée avec une valeur aléatoire
def life_up(self):
self.life_incremental = self.life + random.randint(1, 5) * self.luck
self.life = self.life + self.life_incremental
print(f'Dieu a pris le parti! ({self.name}La vie{self.life_incremental}J'ai récupéré! )')
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}Abattu un monstre de loin!')
print(f'{self.name}Mana sucé par un monstre!')
def drain(self):
self.mana_incremental = self.mana + random.randint(1, 5) * self.suction_power
self.mana = self.mana + self.mana_incremental
print(f'Dieu a pris le parti!{self.name}Mana{self.mana_incremental}J'ai récupéré! )')
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()
résultat
Kirito a frappé le monstre!
Monstre congelé de Kirito!
Kirito a empêché l'attaque!
Kirito a été attaqué!
Kirito a massacré un monstre avec un savoir-faire rapide!
Kirito a volé le monstre de la vie!
Dieu a pris le parti! (La vie de Kirito a récupéré 319!)
------------------------------
Shinon a frappé le monstre!
Monstre Shinon gelé!
Attaque de Shinon empêchée!
J'ai eu une attaque de Shinon!
Shinon a massacré un monstre de loin!
Shinon a sucé le mana du monstre!
Dieu a pris le parti! Shinon a récupéré 375 points de mana! )
Créez une classe HalfElf
qui hérite plusieurs fois de la classe Human
et de la classe ʻElf`.
** Ce que je veux faire, c'est créer une race: demi elfe qui possède tous les attributs et méthodes spécifiques à la race ainsi que les attributs et méthodes partagés **
D'abord, héritons de Human
et de ʻElf sans toucher
__init __`.
Ne touchez pas l'initialiseur
class HalfElf(Human, Elf):
def super_drain(self):
self.super_drain = (self.luck + self.suction_power) * random.randint(1, 5)
print(f'Dieu a pris le parti!{self.name}Mana des monstres{self.super_drain}Je l'ai sucé!')
print(HalfElf.__mro__)
# (<class '__main__.HalfElf'>, <class '__main__.Human'>, <class '__main__.Elf'>, <class '__main__.Race'>, <class 'object'>)
Il semble que vous cherchiez d'abord «Humain».
Dans l'héritage multiple, les classes appelées par super (propre classe, self)
changent dans l'ordre de MRO, donc super () .__ init__
de la classe Human
devient un paramètre de __init__
de la classe ʻElf. Tente de transmettre sa propre valeur. Cependant, la
puissance_aspiration qui existe dans ʻElf
n'est pas dans Humain
, et inversement, la chance
qui existe dans Humain
n'est pas dans ʻElf`, donc elle lance juste une erreur.
Pour le résoudre, vous devez utiliser super ()
dans le code ci-dessus et passer le nom de classe approprié à l'argument de super ()
.
Plus à ce sujet plus tard.
Quels sont les attributs de «HalfElf»?
asuna = HalfElf()
# TypeError: __init__() missing 6 required positional arguments: 'name', 'age', 'life', 'mana', 'stamina', and 'luck'
Les attributs ont «name», «age», «life», «mana», «stamina», «luck». N'a pas aspiration_power
.
Parce qu'il appelle Human 'init`.
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'] C'est devenu ".
Tout a été repris.
aspiration_power
n'est pas pris en charge?Puisqu'il ne décrit pas l'initialiseur, il sera exactement le même que l'initialiseur de classe Human qui est recherché en premier dans MRO, donc aspiration_power
ne sera pas hérité.
De plus, pour l'héritage unique, Human
devrait utiliser super
pour appeler l'initialiseur de la classe de base Race
, mais cette fois c'est un héritage multiple, donc il appelle ʻElf` selon la racine de MRO. .. Cependant, l'attribut «puissance_aspiration» n'existe pas dans «Humain». Par conséquent, il génère toujours une erreur au moment de l'instance.
error
class HalfElf(Human, Elf):
def super_drain(self):
self.super_drain = (self.luck + self.suction_power) * random.randint(5, 10)
print(f'Dieu a pris le parti!{self.name}Mana des monstres{self.super_drain}Je l'ai sucé!')
asuna = HalfElf('Asuna', 18, 200, 300, 200, 10, suction_power=10)
# TypeError: __init__() got an unexpected keyword argument 'suction_power'
#Aspiration sur les propriétés humaines_Parce qu'il n'y a pas de pouvoir
asuna = HalfElf('Asuna', 18, 200, 300, 200, 10)
# TypeError: __init__() missing 1 required positional argument: 'suction_power'
#Il y a une propriété de la classe Elf que vous appelez_Parce qu'aucune valeur n'a été passée au pouvoir
suna = HalfElf('Asuna', 18, 200, 300, 200, 10, 10)
# TypeError: __init__() takes 7 positional arguments but 8 were given
#Parce que la classe Humaine a 7 arguments en tout
Je pense que cela ne fonctionne pas bien car les propriétés définies dans les deux classes parentes sont différentes et la route de recherche de méthode de plusieurs héritages change dans l'ordre de MRO. (difficile....!!)
Pour résoudre ce problème, nous avons procédé comme suit:
super(HalfElf, self).__init__()
J'ai appelé l'initialiseur de la classe suivante Human
de ma classe.
Dans ce cas, l'initialiseur de classe Human est appelé. Cependant, lors de l'appel de la classe ʻElf avec
superdans la classe
Human, la propriété de
super () .__ init__ (dans ce cas) n'a pas de puissance_spiration
et ne correspond pas à la propriété de ʻElf`, donc une erreur se produit. Je vais sortir.
(Peut-être ... je ne comprends pas clairement ...)
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'Dieu a pris le parti!{self.name}Mana des monstres{self.super_drain}Je l'ai sucé!')
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__()
Appelé l'initialiseur de la classe suivante ʻElfde la classe Human. Dans Elf,
super appelle la classe
Race, mais comme les propriétés de la classe ʻElf
satisfont les propriétés de la classe Race
, aucune erreur n'est placée. Au lieu de cela, la chance de la classe Human
n'a pas du tout été prise en charge, donc je la compléterai à nouveau par self.luck = luck
.
A bien fonctionné
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'Dieu a pris le parti!{self.name}Mana des monstres{self.super_drain}Je l'ai sucé!')
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 a frappé le monstre!
Monstre Asuna gelé!
Attaque Asuna empêchée!
J'ai eu une attaque Asuna!
Asuna a abattu un monstre avec un savoir-faire rapide!
Asuna a volé le monstre de la vie!
Dieu a pris le parti! (La vie d'Asuna a récupéré 229!)
J'ai massacré un monstre à distance!
J'ai sucé le mana d'un monstre!
Dieu a pris le parti! Asuna a récupéré 330 points de mana! )
Dieu a pris le parti! Asuna a sucé 200 mana du monstre!
'''
Je pensais que si j'héritais de «Human» et «Elf», je pourrais facilement créer «HalfElf», mais ce n'était pas du tout le cas et c'était très difficile. La réécriture du code de la classe de base pour créer un héritage multiple affectera un autre code, je voudrais donc en savoir plus sur la façon d'écrire une classe. Ensuite, je veux essayer Mixin.
Recommended Posts