Héritage Python
Introduction
L’héritage est un autre concept clé de la programmation orientée objet, et il joue un rôle essentiel dans la construction de classes. Il permet à une classe d’être basée sur une classe existante.
Lorsque vous avez commencé à écrire des classes Python, on vous a dit de simplement mettre « Object » entre parenthèses de la définition de la classe et de ne pas trop y penser. Eh bien, c’est le moment de commencer à y réfléchir.
« Object » est en fait la classe de base dont toutes les classes Python héritent. Il définit un ensemble de fonctionnalités de base que toutes les classes Python doivent avoir. En héritant de celle-ci lorsque vous créez une nouvelle classe, vous vous assurez que cette classe dispose de cette fonctionnalité de base.
En bref, l’héritage est un bon moyen de catégoriser les classes et de s’assurer que vous ne vous répétez pas inutilement.
Qu’est-ce que l’héritage ?
L’héritage existe aussi dans le monde réel. Les deux premiers guides ont utilisé une voiture comme exemple de classe. Eh bien, que se passe-t-il si vous voulez des types de voitures plus spécifiques qui partagent tous ces principes de base d’une voiture ? L’héritage peut aider.
Vous pouvez commencer avec une classe « Voiture » de base qui possède toutes les propriétés que chaque voiture partage. Tout cela serait très général.
Une fois que vous avez votre « Car », vous pouvez créer de nouvelles classes et leur passer « Car ». Elles auront toutes les mêmes propriétés que la classe « Car » de base. Ensuite, vous pouvez ajouter toutes les propriétés supplémentaires que vous souhaitez à ces classes plus spécialisées. Par exemple, vous pouvez avoir des classes « Camion », « Muscle Car » et « SUV » qui héritent toutes de « Voiture ».
Quand on y pense en termes réels, les camions, les muscle cars et les SUV ont tous les mêmes propriétés de base que n’importe quelle autre voiture, mais ils ont aussi des propriétés spécialisées.
Vous pouvez également vous spécialiser davantage. Il existe des tonnes de différents types de camions. Ainsi, vous pouvez créer des classes plus spécialisées qui héritent de « Truck ». Ils commenceront tous avec tout ce qui est de « Car » et tout ce qui vient de « Truck ».
Utilisation de l’héritage en Python
D’accord, maintenant vous pouvez essayer cela avec du vrai code. Configurez une classe « Car » de base qui hérite de « Object ». Essayez de travailler avec l’exemple ci-dessous.
class Car(object):
def __init__(self, make = 'Ford', model = 'Pinto', year = '1971', mileage = 253812, color = 'orange'):
self.__make = make
self.__model = model
self.__year = year
self.__mileage = mileage
self.__color = color
def move_forward(self, speed):
print("Your %s is moving forward at %s" % (self.__model, speed))
def move_backward(self, speed):
print("Moving backward at %s" % speed)
class MuscleCar(Car):
__hp = 300
def set_hp(self, hp):
self.__hp = hp
def get_hp(self):
return self.__hp
def drag_race(self, opponent):
if (self.__hp > opponent.get_hp()):
return "You Win!"
else:
return "You Lose!"
mynewcar = MuscleCar('Ford', 'Mustang', '2016', 3000, 'red')
mynewcar.set_hp(687)
opponent = MuscleCar('Ford', 'Mustang', '2014', 6400, 'green')
opponent.set_hp(465)
mynewcar.move_forward('25mph')
print(mynewcar.drag_race(opponent))
Notez que les objets MuscleCar ont pu utiliser le constructeur et la méthode move_forward de la classe « Car » même si la classe à partir de laquelle ils ont été instanciés ne les a pas explicitement eus.
Primordial
Ce n’est pas parce qu’une classe hérite d’une autre que vous êtes coincé avec toutes les fonctionnalités de la classe parente. Vous pouvez remplacer des parties de la classe parente dans les classes enfants. Les modifications appliquées à la classe enfant ne s’appliqueront pas à la classe parente d’origine, vous n’avez donc pas à vous soucier de gâcher d’autres classes.
Dans l’exemple ci-dessus, la « MuscleCar » avait juste une variable, __hp flottait simplement là sans aucun moyen de la définir sur l’instanciation. Regardez le même exemple, mais avec le constructeur remplacé.
class Car(object):
def __init__(self, make = 'Ford', model = 'Pinto', year = '1971', mileage = 253812, color = 'orange'):
self.__make = make
self.__model = model
self.__year = year
self.__mileage = mileage
self.__color = color
def move_forward(self, speed):
print("Your %s is moving forward at %s" % (self.__model, speed))
def move_backward(self, speed):
print("Moving backward at %s" % speed)
class MuscleCar(Car):
def __init__(self, make = 'Ford', model = 'Mustang', year = '1965', mileage = 54032, color = 'blue', hp = 325):
self.__make = make
self.__model = model
self.__year = year
self.__mileage = mileage
self.__color = color
self.__hp = hp
def set_hp(self, hp):
self.__hp = hp
def get_hp(self):
return self.__hp
def drag_race(self, opponent):
if (self.__hp > opponent.get_hp()):
return "You Win!"
else:
return "You Lose!"
mynewcar = MuscleCar('Ford', 'Mustang', '2016', 3000, 'red', 687)
opponent = MuscleCar()
mynewcar.move_forward('25mph')
print(mynewcar.drag_race(opponent))
Il y a deux choses à remarquer. Tout d’abord, __hp est devenu self.__hp et est incorporé dans le constructeur. Pour cette raison, le réglage est beaucoup plus facile. Deuxièmement, les valeurs par défaut d’une nouvelle « MuscleCar » ont été modifiées. Une Pinto n’est pas une très bonne muscle car par défaut, n’est-ce pas ?
Vous pouvez le faire avec n’importe quelle variable ou méthode d’une sous-classe ou d’une classe enfant. Cela ajoute un degré supplémentaire de flexibilité et vous empêche d’être enfermé dans les fonctionnalités de la classe parente ou super.
La Super Méthode
Parfois, vous avez besoin d’accéder aux méthodes trouvées dans la classe parente à partir de la classe enfant. Prenons l’exemple précédent qui remplace ce constructeur. Une grande partie de ce code est redondante. L’utilisation de super() pour appeler le constructeur de la classe « Car » élimine cette redondance et permet d’obtenir une classe plus rationalisée.
super() peut aussi simplement être utilisé pour accéder aux méthodes normales à utiliser dans les méthodes de sous-classe. L’exemple ci-dessous utilisait super() dans les deux sens.
class Car(object):
def __init__(self, make = 'Ford', model = 'Pinto', year = '1971', mileage = 253812, color = 'orange'):
self.__make = make
self.__model = model
self.__year = year
self.__mileage = mileage
self.__color = color
def set_make(self, make):
self.__make = make
def get_make(self):
return self.__make
def set_model(self, model):
self.__model = model
def get_model(self):
return self.__model
def set_year(self, year):
self.__year = year
def get_year(self):
return self.__year
def set_mileage(self, mileage):
self.__mileage = mileage
def get_mileage(self):
return self.__mileage
def set_color(self, color):
self.__color = color
def get_color(self):
return self.__color
def move_forward(self, speed):
print("Your %s is moving forward at %s" % (self.__model, speed))
def move_backward(self, speed):
print("Moving backward at %s" % speed)
class MuscleCar(Car):
def __init__(self, make = 'Ford', model = 'Mustang', year = '1965', mileage = 54032, color = 'blue', hp = 325):
super().__init__(make, model, year, mileage, color)
self.__hp = hp
def set_hp(self, hp):
self.__hp = hp
def get_hp(self):
return self.__hp
def drag_race(self, opponent):
if (self.__hp > opponent.get_hp()):
return "You Win!"
else:
return "You Lose!"
def trade_up(self, year, color):
super().set_year(year)
super().set_color(color)
super().set_mileage(0)
mynewcar = MuscleCar('Ford', 'Mustang', '2016', 3000, 'red', 687)
opponent = MuscleCar()
mynewcar.move_forward('25mph')
print(mynewcar.drag_race(opponent))
mynewcar.trade_up('2017', 'black')
print("My new %s muscle car is %s and has %d miles" % (mynewcar.get_year(), mynewcar.get_color(), mynewcar.get_mileage()))
Regardez la façon dont la méthode trade_up utilise super() pour accéder et appeler ces méthodes setter à partir de la classe parente.
Réflexions finales
L’héritage vous permet d’utiliser des classes comme modèles pour des classes plus spécialisées. Vous pouvez construire des classes dans une structure telle qu’elles commencent à ressembler à un arbre généalogique, les membres les plus âgés et les plus généraux transmettant des traits aux membres plus jeunes et plus spécialisés.
Une grande partie de la programmation orientée objet consiste à réduire la quantité de code écrite et à empêcher la réécriture d’autant de code que possible. L’héritage joue un rôle important dans cette possibilité.
Exercices
- Créez une classe de base qui hérite de la classe « Car ».
- Instanciez votre nouvelle classe et appelez l’une des méthodes à partir de « Car ».
- Créez une nouvelle méthode dans votre classe enfant.
- Appelez votre nouvelle méthode.
- Utilisez
super()pour ajouter des variables au constructeur de votre classe enfant. - Créez une méthode en utilisant
super()pour accéder aux méthodes de la classe parente. - Appelez votre nouvelle méthode qui utilise
super().