Contactez-nous

Méthodes spéciales (dunder methods : __str__, __repr__, ...)

Découvrez les méthodes spéciales en Python (dunder methods, avec des doubles tirets de soulignement). Apprenez à utiliser __str__, __repr__, __len__, __add__, __eq__, et bien d'autres, pour personnaliser le comportement de vos objets.

Que sont les méthodes spéciales ? Définition et rôle

Les méthodes spéciales, également appelées "méthodes magiques" ou "dunder methods" (pour "double underscore methods"), sont des méthodes prédéfinies en Python qui ont une signification particulière. Elles permettent de personnaliser le comportement de vos objets et de les faire interagir avec les opérateurs et les fonctions intégrées de Python.

Les méthodes spéciales sont reconnaissables à leur nom, qui commence et se termine par deux tirets de soulignement (par exemple, `__init__`, `__str__`, `__add__`).

En définissant des méthodes spéciales dans vos classes, vous pouvez :

  • Contrôler la façon dont vos objets sont affichés (avec `print` et `str`).
  • Définir comment vos objets se comportent avec les opérateurs (comme `+`, `-`, `*`, `==`, `<`, etc.).
  • Permettre à vos objets d'être utilisés dans des contextes spécifiques (par exemple, avec `len`, `with`, etc.).
  • Et bien plus encore...

Les méthodes spéciales sont un mécanisme puissant qui permet à vos objets de s'intégrer harmonieusement avec le reste de Python.

__str__ et __repr__ : représenter vos objets sous forme de chaînes

Les méthodes `__str__` et `__repr__` permettent de définir comment vos objets sont représentés sous forme de chaînes de caractères.

  • `__str__(self)` : Retourne une représentation "informelle" de l'objet, destinée à être lue par un utilisateur humain. Elle est appelée par la fonction intégrée `str()` et par `print()`. Si `__str__` n'est pas définie, Python utilise `__repr__`.
  • `__repr__(self)` : Retourne une représentation "officielle" de l'objet, destinée à être non ambiguë et, idéalement, à pouvoir être utilisée pour recréer l'objet (avec `eval`, par exemple). Elle est appelée par la fonction intégrée `repr()` et par l'interpréteur interactif lorsqu'il affiche un objet.

Exemple :

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return f"Point({self.x}, {self.y})"  # Représentation informelle

    def __repr__(self):
        return f"Point(x={self.x}, y={self.y})"  # Représentation officielle

p = Point(2, 3)

print(p)        # Utilise __str__ : affiche Point(2, 3)
print(str(p))   # Utilise __str__ : affiche Point(2, 3)
print(repr(p))  # Utilise __repr__ : affiche Point(x=2, y=3)

# Dans l'interpréteur interactif :
# >>> p
# Point(x=2, y=3)  (affiche la représentation de __repr__)

Il est recommandé de toujours définir au moins `__repr__` pour vos classes. Si vous ne définissez pas `__str__`, la représentation de `__repr__` sera utilisée à la place.

__len__ : définir la longueur d'un objet

La méthode spéciale `__len__` permet de définir ce que retourne la fonction intégrée `len()` lorsqu'elle est appliquée à un objet de votre classe.

Elle doit retourner un entier positif ou nul, représentant la "longueur" de l'objet (le nombre d'éléments qu'il contient, par exemple).

Exemple :

class MaListe:
    def __init__(self, elements):
        self.elements = elements

    def __len__(self):
        return len(self.elements)

l = MaListe([1, 2, 3, 4])
print(len(l))  # Affiche 4 (appelle l.__len__())

Si vous définissez une classe qui représente une collection d'éléments, il est généralement judicieux de définir `__len__`.

Surcharger les opérateurs : __add__, __eq__, __lt__, etc.

Les méthodes spéciales permettent de *surcharger* les opérateurs, c'est-à-dire de définir comment les opérateurs standard de Python (comme `+`, `-`, `*`, `/`, `==`, `!=`, `<`, `>`, etc.) se comportent avec les objets de votre classe.

Par exemple :

  • `__add__(self, other)` : Définit le comportement de l'opérateur `+` (addition).
  • `__sub__(self, other)` : Définit le comportement de l'opérateur `-` (soustraction).
  • `__mul__(self, other)` : Définit le comportement de l'opérateur `*` (multiplication).
  • `__truediv__(self, other)` : Définit le comportement de l'opérateur `/` (division).
  • `__eq__(self, other)` : Définit le comportement de l'opérateur `==` (égalité).
  • `__ne__(self, other)` : Définit le comportement de l'opérateur `!=` (différent de).
  • `__lt__(self, other)` : Définit le comportement de l'opérateur `<` (inférieur à).
  • `__le__(self, other)` : Définit le comportement de l'opérateur `<=` (inférieur ou égal à).
  • `__gt__(self, other)` : Définit le comportement de l'opérateur `>` (supérieur à).
  • `__ge__(self, other)` : Définit le comportement de l'opérateur `>=` (supérieur ou égal à).
  • Et bien d'autres...

Exemple (surcharge de `+` pour une classe `Vecteur`) :

class Vecteur:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __add__(self, other):
        """Définit l'addition de deux vecteurs."""
        return Vecteur(self.x + other.x, self.y + other.y)

    def __str__(self):
      return f'Vecteur({self.x}, {self.y})'

v1 = Vecteur(2, 3)
v2 = Vecteur(4, 1)
v3 = v1 + v2  # Utilise la méthode __add__
print(v3)      # Affiche Vecteur(6, 4)

En surchargeant les opérateurs, vous pouvez faire en sorte que vos objets se comportent de manière naturelle et intuitive avec les opérateurs standard de Python.

Autres méthodes spéciales courantes

Voici quelques autres méthodes spéciales courantes (liste non exhaustive) :

  • `__getitem__(self, key)` : Permet d'accéder à un élément par index ou par clé (comme pour les listes et les dictionnaires) : `objet[key]`.
  • `__setitem__(self, key, value)` : Permet de modifier un élément par index ou par clé : `objet[key] = valeur`.
  • `__delitem__(self, key)` : Permet de supprimer un élément par index ou par clé : `del objet[key]`.
  • `__contains__(self, item)` : Permet de tester l'appartenance avec l'opérateur `in` : `item in objet`.
  • `__iter__(self)` : Retourne un itérateur pour l'objet (rend l'objet itérable).
  • `__next__(self)` : Retourne l'élément suivant de l'itérateur (utilisé en conjonction avec `__iter__`).
  • `__call__(self, ...)` : Permet d'appeler un objet comme une fonction : `objet()`.
  • `__enter__(self)` et `__exit__(self, exc_type, exc_value, traceback)` : Utilisées pour la gestion des contextes avec l'instruction `with`.

La liste complète des méthodes spéciales est disponible dans la documentation officielle de Python. En utilisant ces méthodes, vous pouvez créer des objets qui s'intègrent parfaitement avec le langage Python et qui offrent une interface intuitive et puissante.