
Débogage avec pdb (Python Debugger)
Apprenez à utiliser pdb, le débogueur interactif intégré à Python. Définissez des points d'arrêt, exécutez votre code pas à pas, inspectez les variables, et identifiez les causes des bugs.
Qu'est-ce que pdb ? Un débogueur interactif
`pdb` (Python Debugger) est le débogueur interactif en ligne de commande inclus dans la bibliothèque standard Python. Il vous permet de :
- Exécuter votre code pas à pas (ligne par ligne, ou instruction par instruction).
- Définir des points d'arrêt (breakpoints) pour interrompre l'exécution à des endroits spécifiques.
- Inspecter la valeur des variables à tout moment.
- Afficher la pile d'appels (call stack).
- Evaluer des expressions Python dans le contexte courant.
- Modifier la valeur des variables (avec prudence !).
- Continuer l'exécution jusqu'à la prochaine instruction, jusqu'à la fin de la fonction, ou jusqu'à la prochaine erreur.
pdb est un outil puissant pour comprendre le comportement de votre code et pour identifier les causes des bugs. Il est particulièrement utile pour les erreurs logiques, difficiles à trouver avec de simples instructions `print`.
pdb est un débogueur *en ligne de commande*. Il existe également des débogueurs graphiques (intégrés à des IDE comme VS Code, PyCharm, etc.), mais pdb est un outil fondamental à connaître.
Démarrer pdb : différentes méthodes
Il existe plusieurs façons de démarrer le débogueur pdb :
- Depuis la ligne de commande : Exécutez votre script avec `python -m pdb mon_script.py`. Cela démarre pdb juste avant la première instruction de votre script.
- En insérant un point d'arrêt dans le code : Ajoutez l'instruction `import pdb; pdb.set_trace()` à l'endroit où vous voulez que le débogueur s'arrête. Lorsque Python rencontre cette instruction, il démarre pdb. (En Python 3.7+, vous pouvez utiliser la fonction intégrée `breakpoint()` au lieu de `import pdb; pdb.set_trace()`).
- Depuis l'intérieur d'une exception : Si une exception non gérée se produit, vous pouvez démarrer pdb en mode "post-mortem" avec `python -m pdb -c continue mon_script.py`. Cela vous permet d'inspecter l'état du programme au moment de l'exception.
Exemple (démarrage avec `python -m pdb`) :
python -m pdb mon_script.pyExemple (insertion d'un point d'arrêt avec `pdb.set_trace()`) :
def ma_fonction(x):
y = x * 2
import pdb; pdb.set_trace() # Le débogueur s'arrêtera ici
z = y + 5
return zExemple (insertion d'un point d'arrêt avec `breakpoint()`, Python 3.7+) :
def ma_fonction(x):
y = x * 2
breakpoint() # Le débogueur s'arrêtera ici
z = y + 5
return zLorsque pdb démarre, il affiche une invite de commande `(Pdb)`. Vous pouvez alors entrer des commandes pdb pour contrôler l'exécution et inspecter l'état du programme.
Commandes pdb de base : n, s, c, p, q, b, l, h
Voici quelques-unes des commandes pdb les plus courantes :
- `h(elp)` : Affiche l'aide (la liste des commandes disponibles). `help commande` affiche l'aide sur une commande spécifique.
- `n(ext)` : Exécute la ligne suivante du programme. Si la ligne suivante est un appel de fonction, `next` exécute la fonction *entièrement* et s'arrête à la ligne suivante dans le contexte courant.
- `s(tep)` : Exécute la ligne suivante du programme. Si la ligne suivante est un appel de fonction, `step` entre *dans* la fonction et s'arrête à la première ligne de la fonction.
- `c(ontinue)` : Continue l'exécution jusqu'au prochain point d'arrêt (ou jusqu'à la fin du programme).
- `b(reak)` : Définit un point d'arrêt. `break` (sans argument) liste les points d'arrêt. `break ligne` définit un point d'arrêt à la ligne spécifiée. `break fichier:ligne` définit un point d'arrêt à la ligne spécifiée dans le fichier spécifié. `break fonction` définit un point d'arrêt au début de la fonction spécifiée. `break condition` définit un point d'arrêt conditionnel.
- `tbreak` : Définit un point d'arrêt temporaire (qui est supprimé automatiquement après avoir été atteint une fois).
- `cl(ear)` : Supprime un ou plusieurs points d'arrêt. `clear` (sans argument) supprime tous les points d'arrêt. `clear numero` supprime le point d'arrêt avec le numéro spécifié.
- `p(rint) expression` : Evalue l'expression et affiche sa valeur.
- `pp expression` : Comme `p`, mais utilise `pprint` (pretty-print) pour afficher la valeur (plus lisible pour les structures de données complexes).
- `l(ist)` : Affiche le code source autour de la ligne courante. `list ligne_debut, ligne_fin` affiche les lignes spécifiées.
- `w(here)` (ou `bt`) : Affiche la pile d'appels (la séquence des appels de fonctions qui ont mené à la ligne courante).
- `u(p)` : Remonte d'un niveau dans la pile d'appels.
- `d(own)` : Descend d'un niveau dans la pile d'appels.
- `a(rgs)` : Affiche les arguments de la fonction courante.
- `q(uit)` : Quitte le débogueur (et termine le programme).
- `r(eturn)` : Continue l'exécution jusqu'à la fin de la fonction en cours.
- `j(ump) ligne` : Saute à la ligne spécifiée (attention, cela peut perturber le flux normal d'exécution).
Il existe de nombreuses autres commandes pdb (voir la documentation de `pdb` pour la liste complète).
Vous pouvez abréger les commandes en utilisant leur(s) première(s) lettre(s) (par exemple, `n` pour `next`, `b` pour `break`, `p` pour `print`, etc.).
Exemple de session de débogage avec pdb
Voici un exemple de session de débogage avec `pdb` :
# mon_script.py
def fonction_avec_bug(x):
y = x * 2
z = y / (x - 2) # Potentielle division par zéro
return z
resultat = fonction_avec_bug(2) # Appelons la fonction avec une valeur problématique
print(resultat)Exécution avec `python -m pdb mon_script.py` :
python -m pdb mon_script.py
> /chemin/vers/mon_script.py(1)()
-> def fonction_avec_bug(x):
(Pdb) b 3 # Définit un point d'arrêt à la ligne 3
Breakpoint 1 at /chemin/vers/mon_script.py:3
(Pdb) c # Continue l'exécution jusqu'au point d'arrêt
> /chemin/vers/mon_script.py(3)fonction_avec_bug()
-> z = y / (x - 2) # Potentielle division par zéro
(Pdb) p x # Affiche la valeur de x
2
(Pdb) p y # Affiche la valeur de y
4
(Pdb) n # Exécute la ligne suivante
ZeroDivisionError: division by zero
> /chemin/vers/mon_script.py(3)fonction_avec_bug()
-> z = y / (x - 2)
(Pdb) q # Quitte le débogueur Dans cet exemple :
- On démarre `pdb` avec `python -m pdb mon_script.py`.
- On définit un point d'arrêt à la ligne 3 avec la commande `b 3`.
- On continue l'exécution jusqu'au point d'arrêt avec la commande `c`.
- On inspecte les valeurs de `x` et `y` avec la commande `p`.
- On exécute la ligne suivante avec la commande `n`, ce qui provoque une `ZeroDivisionError`.
- On quitte le débogueur avec la commande `q`.
pdb vous permet d'inspecter l'état du programme à n'importe quel moment, d'exécuter le code pas à pas, et de comprendre ce qui se passe.
Points d'arrêt conditionnels
Il est possible de définir des points d'arrêt conditionnels. Dans ce cas, le debugger ne s'arrêtera que si une condition est remplie.
Exemple :
import pdb
def ma_fonction(x):
y = x*2
z = x + y
return z
pdb.set_trace()
resultat = ma_fonction(5)Dans la console pdb:
(Pdb) break 4, x > 4 # S'arrête à la ligne 4 si x est supérieur à 4.Bonnes pratiques et limitations
Quelques bonnes pratiques et limitations de pdb:
- Utilisez des points d'arrêt : Au lieu d'exécuter le code ligne par ligne, définissez des points d'arrêt aux endroits stratégiques où vous voulez inspecter l'état du programme.
- Inspectez les variables : Utilisez `p` ou `pp` pour afficher les valeurs des variables et comprendre ce qui se passe.
- Utilisez `l` (list) : Pour visualiser le code autour du point d'arrêt.
- Utilisez la pile d'appels (`w` ou `bt`) : Pour comprendre comment vous êtes arrivé à la ligne courante.
- N'ayez pas peur de modifier le code : pdb vous permet de modifier la valeur des variables (avec `p variable = nouvelle_valeur`), mais faites-le avec prudence.
- pdb est un outil interactif : Il n'est pas adapté pour déboguer du code en production.
- pdb a des limitations : Il peut être difficile de déboguer du code multithreadé ou asynchrone avec pdb. Dans ces cas, d'autres outils de débogage peuvent être plus appropriés.
pdb est un outil puissant pour comprendre et déboguer votre code Python. Il est particulièrement utile pour les erreurs logiques, où le programme ne plante pas mais ne se comporte pas comme prévu. En combinant `pdb` avec de bonnes pratiques de codage, des tests unitaires, et une approche méthodique, vous serez en mesure de résoudre efficacement les problèmes dans votre code.