En Python, il existe trois approches pour invoquer des méthodes d'une classe parente depuis une classe enfant :
- Utilisation du nom explicite de la classe parente :
NomParent.methode(self) - Appel via
super(NomEnfant, self).methode() - Recours à
super().methode()(syntaxe simplifiée pour les classes modernes)
Remarque : super() déclenche par défaut la méthode du premier parent direct, ce qui convient à l'héritage simple ou lorsque seul le parent immédiat est requis.
Exemple de code illustrant ces techniques :
# Classe parente : artisanat traditionnel
class Artisan(object):
def preparer_gateau(self):
print("Gâteau selon la tradition")
# Classe parente : formation moderne
class Formation(object):
def preparer_gateau(self):
print("Gâteau contemporain")
# Classe dérivée : apprenti
class Apprenti(Artisan, Formation):
def preparer_gateau(self):
print("Gâteau signature de l'apprenti")
Artisan.preparer_gateau(self)
Formation.preparer_gateau(self)
def preparer_gateau_ancien(self):
# Approche 1 : valable pour héritage simple ou multiple
# Artisan.preparer_gateau(self)
# super() cible le premier parent par défaut (utile en héritage simple ou pour n'utiliser que ce parent)
# Approche 2 : pour les classes modernes
# Syntaxe : super(NomEnfant, self).methode()
# super(Apprenti, self).preparer_gateau()
# Approche 3 : raccourci pour les classes modernes (identique à l'approche 2)
super().preparer_gateau()
def preparer_gateau_recent(self):
super().preparer_gateau()
# Instanciation d'un objet
apprenti_test = Apprenti()
apprenti_test.preparer_gateau()
# apprenti_test.preparer_gateau_ancien()
# apprenti_test.preparer_gateau_recent()
Examinons ensuite l'usage de super() pour les méthodes constructrices (__init__).
Voici un cas problématique :
class Individu:
def __init__(self, identite):
self.identite = identite
def decrire(self):
print("Je suis un individu, identité :", self.identite)
class Espece:
def __init__(self, regime):
self.regime = regime
def afficher_regime(self):
print("Je suis de cette espèce, alimentation :", self.regime)
# Dans Humain, les attributs et méthodes d'Individu écrasent ceux d'Espece
class Humain(Individu, Espece):
pass
# Création d'un objet
humain = Humain("Jean")
humain.decrire()
humain.afficher_regime()
Résultat de l'exécution :
Je suis un individu, identité : Jean
Traceback (most recent call last):
AttributeError: 'Humain' object has no attribute 'regime'
# La méthode afficher_regime() d'Espece requiert l'attribut regime, mais le constructeur d'Individu a écrasé celui d'Espece, donc regime non initialisé.
Pour résoudre ce problème, la classe enfant doit définir son propre constructeur et appeler explicitement les constructeurs des parents.
- Utilisation de la méthode non liée (appel direct par nom de classe)
- Utilisation de
super(), mais en héritage multiple, cette fontcion ne peut invoquer que le constructeur du premier parent direct.
Ainsi, en héritage multiple, pour le premier parent on peut employer super() ou la méthode non liée, tandis que pour les parents suivnats seule la méthode non liée est utilisable.
class Individu:
def __init__(self, identite):
self.identite = identite
def decrire(self):
print("Je suis un individu, identité :", self.identite)
class Espece:
def __init__(self, regime):
self.regime = regime
def afficher_regime(self):
print("Je suis de cette espèce, alimentation :", self.regime)
class Humain(Individu, Espece):
def __init__(self, identite, regime):
# Appel du constructeur du premier parent via super()
super().__init__(identite)
# Alternative : Individu.__init__(self, identite)
# Appel du constructeur d'Espece par méthode non liée
Espece.__init__(self, regime)
humain = Humain("Marie", "omnivore")
humain.decrire()
humain.afficher_regime()
Résultat :
Je suis un individu, identité : Marie
Je suis de cette espèce, alimentation : omnivore
On constate que pour le constructeur d'Individu, super() ou la méthode non liée fonctionnent, mais pour celui d'Espece la méthode non liée est indispensable.