Qu'est-ce que super() en Python ? Guide complet

Découvrez la fonction super() en Python : comment appeler les méthodes d'une classe parente, gérer l'héritage multiple et écrire du code orienté objet propre.
9 min de lecture
Believemy logo

Définition de super() en Python

La fonction super() est une fonction native de Python qui permet d'accéder aux méthodes et attributs d'une classe parente (ou classe mère) depuis une classe enfant. Elle joue un rôle fondamental dans le mécanisme d'héritage, l'un des piliers de la programmation orientée objet (POO).

Concrètement, lorsque vous créez une classe qui hérite d'une autre, super() vous permet d'appeler les méthodes de la classe parente sans avoir à la nommer explicitement. Cela rend votre code plus flexible, plus maintenable et mieux adapté aux architectures complexes.

Si vous souhaitez maîtriser la programmation orientée objet en Python et toutes ses subtilités, notre formation complète sur Python vous guidera pas à pas dans cet apprentissage.

Bon à savoir

super() retourne un objet proxy temporaire qui délègue les appels de méthode à la classe parente (ou à la classe suivante dans l'ordre de résolution des méthodes, le MRO).

 

Syntaxe de base de super()

La syntaxe de super() a évolué avec les versions de Python. Depuis Python 3, elle est devenue beaucoup plus simple :

Syntaxe Python 3 (recommandée)

PYTHON
class Enfant(Parent):
    def methode(self):
        super().methode()

 

Syntaxe Python 2 (ancienne)

PYTHON
class Enfant(Parent):
    def methode(self):
        super(Enfant, self).methode()

En Python 3, vous n'avez plus besoin de passer la classe et l'instance en arguments. Python le fait automatiquement pour vous. Cependant, la syntaxe avec arguments reste valide et peut être utile dans certains cas avancés.

 

Utilisation de super() avec __init__

Le cas d'utilisation le plus courant de super() est l'appel au constructeur __init__ de la classe parente. Cela permet d'initialiser les attributs hérités avant d'ajouter les attributs spécifiques à la classe enfant.

Exemple simple d'héritage

PYTHON
class Animal:
    def __init__(self, nom, age):
        self.nom = nom
        self.age = age

    def se_presenter(self):
        return f"{self.nom} a {self.age} ans."


class Chien(Animal):
    def __init__(self, nom, age, race):
        super().__init__(nom, age)  # Appel au constructeur parent
        self.race = race

    def se_presenter(self):
        base = super().se_presenter()  # Appel à la méthode parente
        return f"{base} C'est un {self.race}."


mon_chien = Chien("Rex", 5, "Berger Allemand")
print(mon_chien.se_presenter())
# Rex a 5 ans. C'est un Berger Allemand.

Dans cet exemple, la class Chien hérite de Animal. Grâce à super().__init__(nom, age), nous n'avons pas besoin de dupliquer le code d'initialisation de nom et age. La classe enfant se concentre uniquement sur ce qui lui est propre : l'attribut race.

 

Sans super() : ce qu'il ne faut pas faire

PYTHON
# Mauvaise pratique : appel direct à la classe parente
class Chien(Animal):
    def __init__(self, nom, age, race):
        Animal.__init__(self, nom, age)  # Fonctionne, mais déconseillé
        self.race = race
Attention

Appeler directement Animal.__init__(self, ...) fonctionne dans les cas simples, mais pose problème en héritage multiple. Utilisez toujours super() pour garantir un comportement correct.

 

super() et l'héritage multiple

C'est dans le contexte de l'héritage multiple que super() révèle toute sa puissance. Python utilise un algorithme appelé MRO (Method Resolution Order) pour déterminer dans quel ordre les classes parentes sont parcourues.

Le problème du diamant

Le "problème du diamant" survient lorsqu'une classe hérite de deux classes qui héritent elles-mêmes d'une même classe de base :

PYTHON
class A:
    def __init__(self):
        print("A.__init__")
        self.valeur = "A"


class B(A):
    def __init__(self):
        print("B.__init__")
        super().__init__()
        self.valeur_b = "B"


class C(A):
    def __init__(self):
        print("C.__init__")
        super().__init__()
        self.valeur_c = "C"


class D(B, C):
    def __init__(self):
        print("D.__init__")
        super().__init__()
        self.valeur_d = "D"


d = D()
# D.__init__
# B.__init__
# C.__init__
# A.__init__

Grâce à super() et au MRO, chaque constructeur n'est appelé qu'une seule fois, et dans le bon ordre. Sans super(), le constructeur de A aurait pu être appelé deux fois.

 

Vérifier le MRO d'une classe

Vous pouvez inspecter l'ordre de résolution des méthodes avec la méthode mro() ou l'attribut __mro__ :

PYTHON
print(D.mro())
# [<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>]

# Ou avec __mro__
print(D.__mro__)
# (<class 'D'>, <class 'B'>, <class 'C'>, <class 'A'>, <class 'object'>)

Le MRO suit l'algorithme C3 Linearization, qui garantit un ordre cohérent et prévisible. super() suit cet ordre pour déléguer les appels de méthodes.

 

Exemples pratiques avancés

Surcharger une méthode tout en conservant le comportement parent

Un cas très fréquent consiste à étendre le comportement d'une méthode parente plutôt que de la remplacer entièrement :

PYTHON
class Fichier:
    def sauvegarder(self, donnees):
        print(f"Sauvegarde de {len(donnees)} caractères...")
        self.contenu = donnees
        return True


class FichierAvecLog(Fichier):
    def __init__(self):
        super().__init__()
        self.historique = []

    def sauvegarder(self, donnees):
        # Ajouter un comportement avant
        self.historique.append(f"Sauvegarde: {len(donnees)} caractères")
        print(f"[LOG] Tentative de sauvegarde...")

        # Appeler le comportement parent
        resultat = super().sauvegarder(donnees)

        # Ajouter un comportement après
        if resultat:
            print(f"[LOG] Sauvegarde réussie.")
        return resultat


fichier = FichierAvecLog()
fichier.sauvegarder("Bonjour le monde")
# [LOG] Tentative de sauvegarde...
# Sauvegarde de 16 caractères...
# [LOG] Sauvegarde réussie.

 

Utiliser super() avec des propriétés

Vous pouvez aussi utiliser super() avec les propriétés Python (décorateur @property) :

PYTHON
class Personne:
    def __init__(self, prenom, nom):
        self.prenom = prenom
        self.nom = nom

    @property
    def nom_complet(self):
        return f"{self.prenom} {self.nom}"


class Docteur(Personne):
    @property
    def nom_complet(self):
        return f"Dr. {super().nom_complet}"


doc = Docteur("Jean", "Dupont")
print(doc.nom_complet)
# Dr. Jean Dupont

 

super() dans les méthodes de classe et méthodes statiques

PYTHON
class Base:
    compteur = 0

    @classmethod
    def incrementer(cls):
        cls.compteur += 1
        print(f"Base.compteur = {cls.compteur}")


class Derivee(Base):
    @classmethod
    def incrementer(cls):
        super().incrementer()  # Fonctionne aussi avec @classmethod
        print(f"Incrémentation depuis Derivee")


Derivee.incrementer()
# Base.compteur = 1
# Incrémentation depuis Derivee

 

super() avec des arguments : cas avancés

Bien que la syntaxe sans arguments soit préférée en Python 3, la version avec arguments reste utile dans certaines situations :

Accéder à une classe spécifique dans la hiérarchie

PYTHON
class A:
    def saluer(self):
        return "Bonjour de A"


class B(A):
    def saluer(self):
        return "Bonjour de B"


class C(B):
    def saluer(self):
        return "Bonjour de C"

    def saluer_depuis_a(self):
        # Sauter B et aller directement à A
        return super(B, self).saluer()


c = C()
print(c.saluer())              # Bonjour de C
print(c.saluer_depuis_a())     # Bonjour de A
Attention

Sauter des classes dans la hiérarchie avec super(ClasseSpecifique, self) est une technique avancée. Utilisez-la avec prudence car elle peut rendre le code difficile à maintenir.

 

Comparaison : super() vs appel direct

Voici un tableau comparatif pour comprendre pourquoi super() est préférable à l'appel direct de la classe parente :

Critèresuper()Appel direct (Parent.methode())
Héritage simple✅ Fonctionne parfaitement✅ Fonctionne aussi
Héritage multiple✅ Gère correctement le MRO❌ Risque de doublons
Refactorisation✅ Pas besoin de modifier le nom❌ Nom de classe en dur
Maintenabilité✅ Code découplé❌ Couplage fort
Lisibilité✅ Convention standard⚠️ Peut prêter à confusion

 

Bonnes pratiques avec super()

Pour utiliser super() efficacement, voici les règles à suivre :

1. Toujours utiliser super() plutôt que l'appel direct

Même si votre classe n'a qu'un seul parent, utilisez super(). Votre code sera prêt pour l'évolution future.

 

2. Appeler super().__init__() en début de constructeur

En règle générale, initialisez d'abord la classe parente avant d'ajouter vos propres attributs :

PYTHON
class MonWidget(WidgetBase):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)  # D'abord le parent
        self.personnalise = True    # Ensuite vos attributs

 

3. Utiliser des **kwargs pour la compatibilité en héritage multiple

En héritage multiple, chaque classe peut avoir besoin de paramètres différents. Utilisez **kwargs pour transmettre les arguments :

PYTHON
class A:
    def __init__(self, param_a=None, **kwargs):
        super().__init__(**kwargs)
        self.param_a = param_a


class B:
    def __init__(self, param_b=None, **kwargs):
        super().__init__(**kwargs)
        self.param_b = param_b


class C(A, B):
    def __init__(self, param_c=None, **kwargs):
        super().__init__(**kwargs)
        self.param_c = param_c


# Tous les paramètres sont correctement distribués
obj = C(param_a="a", param_b="b", param_c="c")
print(obj.param_a, obj.param_b, obj.param_c)  # a b c

 

4. Ne pas mélanger super() et appels directs

Dans une hiérarchie de classes, si certaines classes utilisent super() et d'autres non, le MRO peut ne pas être respecté correctement. Soyez cohérent.

 

5. Documenter la chaîne d'héritage

Utilisez des docstring pour expliquer pourquoi vous appelez super() et quels arguments sont transmis, surtout en héritage multiple.

 

Erreurs courantes avec super()

Oublier d'appeler super().__init__()

PYTHON
# Erreur : les attributs du parent ne sont pas initialisés
class Enfant(Parent):
    def __init__(self):
        # Oubli de super().__init__()
        self.attribut_enfant = "valeur"

# Résultat : AttributeError quand on accède aux attributs du parent

 

Appeler super() en dehors d'une classe

PYTHON
# Erreur : super() ne fonctionne que dans une classe
def ma_fonction():
    super()  # RuntimeError: super(): no current class

 

Incompatibilité de signatures en héritage multiple

PYTHON
# Problème : signatures incompatibles
class A:
    def __init__(self, x):
        self.x = x

class B:
    def __init__(self, y):
        self.y = y

class C(A, B):
    def __init__(self):
        # Comment passer les bons arguments ?
        super().__init__(x=1)  # B ne reçoit jamais y !

# Solution : utiliser **kwargs comme montré plus haut

 

Questions fréquentes

Question

Quelle est la différence entre super() et le nom de la classe parente ?

super() utilise le MRO (Method Resolution Order) pour déterminer quelle classe parente appeler, ce qui est essentiel en héritage multiple. L'appel direct (Parent.methode(self)) ignore le MRO et appelle toujours la même classe, ce qui peut provoquer des appels multiples ou manquants dans des hiérarchies complexes. En résumé, super() est plus sûr, plus flexible et constitue la pratique recommandée par la communauté Python.

 

Question

Peut-on utiliser super() sans héritage ?

Techniquement, toute classe Python hérite implicitement de object. Donc super() fonctionnera, mais il appellera les méthodes de object, ce qui est rarement utile. En pratique, super() n'a de sens que lorsque votre class hérite explicitement d'une autre classe avec des méthodes que vous souhaitez réutiliser ou étendre.

 

Question

super() fonctionne-t-il avec les méthodes magiques (dunder methods) ?

Oui, super() fonctionne avec toutes les méthodes, y compris les méthodes magiques comme __init__, __str__, __repr__, __eq__, etc. C'est d'ailleurs son utilisation la plus courante : appeler le __init__ parent pour initialiser les attributs hérités. Vous pouvez aussi l'utiliser avec __new__ pour contrôler la création d'instances.

 

Question

Comment apprendre à bien utiliser super() et la POO en Python ?

La maîtrise de super() passe par une bonne compréhension de la programmation orientée objet : héritage, polymorphisme, encapsulation. Nous vous recommandons de suivre notre formation dédiée à Python sur Believemy, qui aborde en profondeur l'héritage, les classes, et toutes les subtilités de super() avec des exercices pratiques et des projets concrets.

Termes connexes

Découvrez notre glossaire Python

Parcourez les termes et définitions les plus couramment utilisés dans le domaine du développement avec Python.

Partager cet article

Tu veux nous aider ? Fais un lien vers cet article sur tes réseaux ou encore mieux : sur ton site, dans un article ou dans ta newsletter.