Qu'est-ce que __str__ en Python ?

Découvrez la méthode spéciale __str__ en Python : définition, exemples pratiques, différence avec __repr__ et bonnes pratiques pour représenter vos objets.
8 min de lecture
Believemy logo

Définition de __str__ en Python

La méthode __str__ est une méthode spéciale (aussi appelée dunder method ou magic method) en Python qui permet de définir la représentation en chaîne de caractères d'un objet. Lorsque vous utilisez la fonction print sur un objet ou que vous appelez str(), Python invoque automatiquement la méthode __str__ de cet objet pour obtenir une représentation lisible et compréhensible par un humain.

En d'autres termes, __str__ vous permet de contrôler ce qui s'affiche lorsqu'un utilisateur demande à voir votre objet sous forme de texte. C'est un concept fondamental de la programmation orientée objet en Python, que vous pouvez approfondir dans notre formation complète sur Python.

Concrètement, sans __str__, l'affichage d'un objet personnalisé ressemble à ceci :

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

u = Utilisateur("Alice", 30)
print(u)
# Résultat : <__main__.Utilisateur object at 0x7f8b8c0d4a90>

Ce résultat n'est pas très parlant. Grâce à __str__, vous pouvez transformer cet affichage en quelque chose de bien plus utile et lisible.

 

Syntaxe et fonctionnement de __str__

La méthode __str__ se définit à l'intérieur d'une class Python. Elle prend uniquement self comme paramètre et doit obligatoirement retourner une chaîne de caractères (str).

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

    def __str__(self):
        return f"{self.nom}, {self.age} ans"

u = Utilisateur("Alice", 30)
print(u)
# Résultat : Alice, 30 ans
Bon à savoir

__str__ doit toujours retourner un objet de type str. Si vous retournez un autre type (un entier, une liste, etc.), Python lèvera une erreur TypeError.

Voici les situations dans lesquelles Python appelle automatiquement __str__ :

Contexte d'appelExempleDescription
print()print(objet)Affiche la représentation textuelle de l'objet
str()str(objet)Convertit l'objet en chaîne de caractères
f-stringf"{objet}"Insère la représentation dans une f-string
format()"{}".format(objet)Utilisé dans le formatage de chaînes

 

Différence entre __str__ et __repr__

L'une des questions les plus fréquentes en Python concerne la différence entre __str__ et __repr__. Ces deux méthodes servent à représenter un objet sous forme de texte, mais elles ont des objectifs fondamentalement différents.

Critère__str____repr__
Public cibleUtilisateur finalDéveloppeur
ObjectifLisibilitéPrécision et non-ambiguïté
Appelé parprint(), str()repr(), console interactive
FallbackAppelle __repr__ si absentAffiche l'adresse mémoire si absent

Voici un exemple concret montrant cette différence :

PYTHON
class Produit:
    def __init__(self, nom, prix):
        self.nom = nom
        self.prix = prix

    def __str__(self):
        return f"{self.nom} — {self.prix} €"

    def __repr__(self):
        return f"Produit(nom='{self.nom}', prix={self.prix})"

p = Produit("Clavier mécanique", 89.99)

print(str(p))   # Clavier mécanique — 89.99 €
print(repr(p))  # Produit(nom='Clavier mécanique', prix=89.99)
Attention

Si vous ne définissez que __repr__ sans __str__, Python utilisera __repr__ comme fallback lorsque __str__ est appelé. L'inverse n'est pas vrai : si seul __str__ est défini, repr() n'utilisera pas __str__.

En règle générale, nous vous recommandons de toujours définir __repr__ en priorité (pour le débogage) et d'ajouter __str__ lorsque vous souhaitez un affichage plus convivial pour l'utilisateur final.

 

Exemples pratiques

Représenter un objet simple

Commençons par un exemple basique avec une classe représentant un livre :

PYTHON
class Livre:
    def __init__(self, titre, auteur, pages):
        self.titre = titre
        self.auteur = auteur
        self.pages = pages

    def __str__(self):
        return f"'{self.titre}' par {self.auteur} ({self.pages} pages)"

livre = Livre("Le Petit Prince", "Saint-Exupéry", 96)
print(livre)
# 'Le Petit Prince' par Saint-Exupéry (96 pages)

 

Utiliser __str__ dans une collection d'objets

Lorsque vous placez des objets dans une list ou un dict, le comportement diffère. À l'intérieur d'une collection, Python utilise __repr__ et non __str__. Voici comment gérer cela :

PYTHON
class Etudiant:
    def __init__(self, nom, moyenne):
        self.nom = nom
        self.moyenne = moyenne

    def __str__(self):
        return f"{self.nom} (moyenne : {self.moyenne}/20)"

    def __repr__(self):
        return self.__str__()

etudiants = [
    Etudiant("Alice", 15.5),
    Etudiant("Bob", 12.0),
    Etudiant("Charlie", 17.8)
]

# Affichage individuel → utilise __str__
for e in etudiants:
    print(e)
# Alice (moyenne : 15.5/20)
# Bob (moyenne : 12.0/20)
# Charlie (moyenne : 17.8/20)

# Affichage de la liste → utilise __repr__
print(etudiants)
# [Alice (moyenne : 15.5/20), Bob (moyenne : 12.0/20), Charlie (moyenne : 17.8/20)]

 

__str__ avec l'héritage de classes

La méthode __str__ peut être héritée et surchargée dans les classes enfants. C'est un mécanisme puissant du polymorphisme en Python :

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

    def __str__(self):
        return f"{self.nom} est un(e) {self.espece}"

class Chien(Animal):
    def __init__(self, nom, race):
        super().__init__(nom, "chien")
        self.race = race

    def __str__(self):
        return f"{super().__str__()} de race {self.race}"

class Chat(Animal):
    def __init__(self, nom, interieur=True):
        super().__init__(nom, "chat")
        self.interieur = interieur

    # Pas de __str__ défini → utilise celui du parent

rex = Chien("Rex", "Berger Allemand")
minou = Chat("Minou")

print(rex)    # Rex est un(e) chien de race Berger Allemand
print(minou)  # Minou est un(e) chat

 

__str__ avec les dataclasses

Les dataclass génèrent automatiquement une méthode __repr__, mais pas de __str__ personnalisée. Si vous souhaitez un affichage différent de celui par défaut, vous devez la définir manuellement :

PYTHON
from dataclasses import dataclass

@dataclass
class Point:
    x: float
    y: float

    def __str__(self):
        return f"Point({self.x}, {self.y})"

p = Point(3.5, 7.2)
print(p)       # Point(3.5, 7.2)
print(repr(p)) # Point(x=3.5, y=7.2)  ← généré automatiquement

 

Exemple avancé : affichage formaté multi-lignes

Rien ne vous empêche de retourner une chaîne multi-lignes dans __str__. C'est particulièrement utile pour les objets complexes :

PYTHON
class Facture:
    def __init__(self, numero, client, lignes):
        self.numero = numero
        self.client = client
        self.lignes = lignes  # liste de tuples (description, montant)

    def total(self):
        return sum(montant for _, montant in self.lignes)

    def __str__(self):
        en_tete = f"Facture #{self.numero} — Client : {self.client}"
        separateur = "-" * 45
        lignes_texte = "\n".join(
            f"  {desc:<30} {montant:>8.2f} €"
            for desc, montant in self.lignes
        )
        total_texte = f"  {'TOTAL':<30} {self.total():>8.2f} €"
        return f"{en_tete}\n{separateur}\n{lignes_texte}\n{separateur}\n{total_texte}"

facture = Facture("2024-001", "Believemy", [
    ("Formation Python", 299.00),
    ("Support premium", 49.99),
    ("Certificat", 19.99)
])

print(facture)
# Facture #2024-001 — Client : Believemy
# ---------------------------------------------
#   Formation Python                  299.00 €
#   Support premium                    49.99 €
#   Certificat                         19.99 €
# ---------------------------------------------
#   TOTAL                             368.98 €

 

Bonnes pratiques

Voici les règles essentielles à suivre lorsque vous implémentez __str__ dans vos classes Python :

  • Retournez toujours un str : C'est une obligation. Tout autre type provoquera une erreur TypeError.
  • Gardez le message concis et lisible : __str__ est destiné à l'utilisateur final, pas au développeur. Évitez les détails techniques superflus.
  • Définissez aussi __repr__ : Ne comptez pas uniquement sur __str__. Implémentez toujours __repr__ pour le débogage.
  • Évitez les effets de bord : La méthode __str__ ne devrait jamais modifier l'état de l'objet. Elle doit être une opération en lecture seule.
  • Utilisez les f-string : Elles sont le moyen le plus lisible et le plus performant pour construire la chaîne de retour.
  • Ne levez pas d'exception : __str__ devrait toujours réussir. Gérez les cas limites (attributs None, listes vides, etc.) avec des valeurs par défaut.
  • Pensez à l'héritage : Si votre classe est destinée à être héritée, concevez __str__ de manière à ce qu'elle puisse être étendue via super().__str__().
Bon à savoir

Une bonne règle à retenir : __str__ répond à la question « Comment présenter cet objet à un utilisateur ? » tandis que __repr__ répond à « Comment recréer cet objet ? ».

 

Erreurs courantes à éviter

Voici les pièges les plus fréquents rencontrés par les développeurs Python lorsqu'ils travaillent avec __str__ :

1. Oublier de retourner une chaîne

PYTHON
# ❌ Mauvais : print au lieu de return
class Mauvais:
    def __str__(self):
        print("Mon objet")  # Ne retourne rien (None)

# ✅ Bon : retourner la chaîne
class Bon:
    def __str__(self):
        return "Mon objet"

 

2. Retourner un type incorrect

PYTHON
# ❌ Mauvais : retourne un entier
class Compteur:
    def __init__(self, valeur):
        self.valeur = valeur

    def __str__(self):
        return self.valeur  # TypeError si valeur n'est pas str !

# ✅ Bon : convertir en chaîne
class Compteur:
    def __init__(self, valeur):
        self.valeur = valeur

    def __str__(self):
        return str(self.valeur)

 

3. Confondre __str__ et __repr__ dans les collections

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

    def __str__(self):
        return self.nom

    # __repr__ non défini !

elements = [Element("A"), Element("B"), Element("C")]
print(elements)
# [<__main__.Element object at 0x...>, ...]
# __str__ n'est PAS utilisé dans les listes !

 

Questions fréquentes

Question

Quelle est la différence entre __str__ et __repr__ en Python ?

__str__ est conçue pour produire une représentation lisible pour l'utilisateur final, tandis que __repr__ vise une représentation non ambiguë pour le développeur, idéalement capable de recréer l'objet. Lorsque vous appelez print ou str(), c'est __str__ qui est invoquée. Dans la console interactive ou via repr(), c'est __repr__. Si __str__ n'est pas définie, Python utilise __repr__ comme fallback.

 

Question

Faut-il toujours définir __str__ dans ses classes Python ?

Ce n'est pas obligatoire, mais c'est fortement recommandé dès que vos objets sont susceptibles d'être affichés. Au minimum, vous devriez toujours définir __repr__ pour faciliter le débogage. Ajoutez __str__ lorsque vous avez besoin d'un affichage convivial différent de la représentation technique. Pour les dataclass, __repr__ est générée automatiquement, ce qui suffit souvent.

 

Question

Peut-on utiliser __str__ avec les types natifs de Python ?

Oui, tous les types natifs de Python (int, float, list, dict, tuple, etc.) possèdent déjà une implémentation de __str__. C'est d'ailleurs grâce à cela que print([1, 2, 3]) affiche [1, 2, 3] au lieu de l'adresse mémoire de l'objet liste. Vous ne pouvez pas modifier __str__ sur les types natifs directement, mais vous pouvez créer des sous-classes si nécessaire.

 

Question

Comment apprendre à maîtriser __str__ et les méthodes spéciales Python ?

Les méthodes spéciales comme __str__, __repr__, __init__, __eq__ ou encore __len__ (liée à len) sont au cœur de la programmation orientée objet en Python. Pour les maîtriser pleinement, nous vous recommandons de suivre notre formation dédiée à Python sur Believemy, qui couvre en détail la création de classes, les méthodes spéciales et les bonnes pratiques de développement Python.

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.