Comment parcourir le code Python pour aider à déboguer les problèmes?

194

En Java / C #, vous pouvez facilement parcourir le code pour tracer ce qui pourrait ne pas aller, et les IDE rendent ce processus très convivial.

Pouvez-vous tracer le code Python de la même manière?

Blankman
la source

Réponses:

274

Oui! Il y a un débogueur Python appelé pdbjuste pour faire ça!

Vous pouvez lancer un programme Python via pdben utilisant pdb myscript.pyou python -m pdb myscript.py.

Il y a quelques commandes que vous pouvez ensuite émettre, qui sont documentées sur la pdbpage.

Quelques exemples utiles à retenir sont:

  • b: définir un point d'arrêt
  • c: continuez le débogage jusqu'à ce que vous atteigniez un point d'arrêt
  • s: parcourir le code
  • n: pour aller à la ligne de code suivante
  • l: liste le code source du fichier courant (par défaut: 11 lignes y compris la ligne en cours d'exécution)
  • u: remonter un cadre de pile
  • d: naviguer dans un cadre de pile
  • p: pour imprimer la valeur d'une expression dans le contexte courant

Si vous ne souhaitez pas utiliser de débogueur de ligne de commande, certains IDE comme Pydev , Wing IDE ou PyCharm ont un débogueur GUI. Wing et PyCharm sont des produits commerciaux, mais Wing a une édition "personnelle" gratuite, et PyCharm a une édition communautaire gratuite.

mit
la source
10
Wow, je ne peux pas croire que j'ai du mal à trouver un pdb graphique pour linux / ubuntu. Est-ce que je manque quelque chose? Je devrais peut-être envisager de créer un plugin SublimeText pour cela.
ThorSummoner
4
PyCharm est assez bon en tant que débogueur graphique, et sa Community Edition est gratuite!
Pieter
@ThorSummoner, pudbc'est génial pour ça. Aussipydev
alpha_989
pdbn'est pas un outil de ligne de commande. Pour l'utiliser, utilisez python -m pdb your_script.py.
jdhao
@jdhao Je suppose que ce n'est pas standard, mais sur Ubuntu, la pdbcommande fait partie du pythonpackage. Dans tous les cas, cela python -m <module>devient la norme pour d'autres choses comme pip, il est donc probablement préférable de l'utiliser par défaut.
wjandrea
55

En utilisant le débogueur interactif Python 'pdb'

La première étape consiste à faire entrer l'interpréteur Python en mode de débogage.

A. Depuis la ligne de commande

Méthode la plus simple, exécutée à partir de la ligne de commande, de l'interpréteur python

$ python -m pdb scriptName.py
> .../pdb_script.py(7)<module>()
-> """
(Pdb)

B. Au sein de l'interprète

Tout en développant les premières versions des modules et en l'expérimentant de manière plus itérative.

$ python
Python 2.7 (r27:82508, Jul  3 2010, 21:12:11)
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pdb_script
>>> import pdb
>>> pdb.run('pdb_script.MyObj(5).go()')
> <string>(1)<module>()
(Pdb)

C. À partir de votre programme

Pour un gros projet et un module de longue durée, vous pouvez démarrer le débogage depuis l'intérieur du programme en utilisant import pdb et set_trace () comme ceci:

#!/usr/bin/env python
# encoding: utf-8
#

import pdb

class MyObj(object):
    count = 5
    def __init__(self):
        self.count= 9

    def go(self):
        for i in range(self.count):
            pdb.set_trace()
            print i
        return

if __name__ == '__main__':
    MyObj(5).go()

Débogage étape par étape pour aller plus en interne

  1. Exécutez l'instruction suivante… avec «n» (suivant)

  2. Répéter la dernière commande de débogage… avec ENTER

  3. Tout quitter … avec «q» (quitter)

  4. Impression de la valeur des variables… avec «p» (impression)

    a) pa

  5. Désactivation de l'invite (Pdb)… avec «c» (continuer)

  6. Voir où vous êtes… avec «l» (liste)

  7. Entrer dans des sous-programmes… avec «s» (entrer dans)

  8. Continuer… mais juste à la fin du sous-programme actuel… avec «r» (retour)

  9. Attribuer une nouvelle valeur

    a) ! b = "B"

  10. Définir un point d'arrêt

    a) pause linge

    b) nom de la fonction de rupture

    c) nom de fichier de rupture: numéro de lin

  11. Point d'arrêt temporaire

    a) numéro de lin

  12. Point d'arrêt conditionnel

    a) pause linge, condition

Remarque: ** Toutes ces commandes doivent être exécutées depuis ** pdb

Pour des connaissances approfondies, reportez-vous: -

https://pymotw.com/2/pdb/

https://pythonconquerstheuniverse.wordpress.com/2009/09/10/debugging-in-python/

akD
la source
42

Il existe un module appelé «pdb» en python. En haut de votre script python, vous faites

import pdb
pdb.set_trace()

et vous entrerez en mode débogage. Vous pouvez utiliser «s» pour faire un pas, «n» pour suivre la ligne suivante, comme vous le feriez avec le débogueur «gdb».

Senthil Kumaran
la source
21

À partir de Python 3.7, vous pouvez utiliser la breakpoint()fonction intégrée pour entrer dans le débogueur:

foo()
breakpoint()  # drop into the debugger at this point
bar()

Par défaut, breakpoint()importera pdbet appellera pdb.set_trace(). Cependant, vous pouvez contrôler le comportement de débogage via sys.breakpointhook()et l'utilisation de la variable d'environnement PYTHONBREAKPOINT.

Voir PEP 553 pour plus d'informations.

Eugène Yarmash
la source
2
Quand j'ai vu, breakpointj'étais excité. Mais ensuite, j'ai appris que ce n'était essentiellement qu'un raccourci import pdb; pdb.set_trace()et cela m'a rendu triste. Développeurs Python: veuillez vous concentrer sur l'amélioration de PDB avec les fonctionnalités de base de GDB telles que les lignes de contexte, l'historique des commandes persistantes et l'auto-complétion des onglets :-)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
11

ipdb (débogueur IPython)

ipdb ajoute la fonctionnalité IPython à pdb, offrant les ÉNORMES améliorations suivantes:

  • achèvement de l'onglet
  • afficher plus de lignes de contexte
  • coloration syntaxique

Tout comme pdg, ipdb est encore loin d'être parfait et complètement rudimentaire si on le compare à GDB, mais c'est déjà une énorme amélioration par rapport à pdb.

L'utilisation est analogue à pdb, installez-la simplement avec:

python3 -m pip install --user ipdb

puis ajoutez à la ligne à partir de laquelle vous souhaitez effectuer le débogage:

__import__('ipdb').set_trace(context=21)

Vous voudrez probablement ajouter un raccourci pour cela à partir de votre éditeur, par exemple pour Vim snipmate que j'ai:

snippet ipd
    __import__('ipdb').set_trace(context=21)

donc je peux taper juste ipd<tab>et il se développe jusqu'au point d'arrêt. Ensuite, il est facile de le supprimer ddpuisque tout est contenu dans une seule ligne.

context=21augmente le nombre de lignes de contexte comme expliqué dans: Comment puis-je faire en sorte qu'ipdb affiche plus de lignes de contexte pendant le débogage?

Alternativement, vous pouvez également déboguer des programmes depuis le début avec:

ipdb3 main.py

mais vous ne voulez généralement pas faire cela parce que:

  • vous devrez parcourir toutes les définitions de fonctions et de classes lorsque Python lit ces lignes
  • Je ne sais pas comment définir la taille du contexte sans pirater ipdb. Patch pour l'autoriser: https://github.com/gotcha/ipdb/pull/155

Ou bien, comme dans raw pdb 3.2+, vous pouvez définir des points d'arrêt à partir de la ligne de commande:

ipdb3 -c 'b 12' -c 'b myfunc' ~/test/a.py

bien qu'il -c csoit cassé pour une raison quelconque: https://github.com/gotcha/ipdb/issues/156

python -m modulele débogage a été demandé à l' adresse : Comment déboguer un module Python exécuté avec python -m à partir de la ligne de commande? et puisque Python 3.7 peut être fait avec:

python -m pdb -m my_module

Graves fonctionnalités manquantes de pdb et ipdb par rapport à GDB:

ennuis spécifiques à ipdb:

Testé sous Ubuntu 16.04, ipdb == 0.11, Python 3.5.2.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
la source
5

Il existe de breakpoint()nos jours une méthode qui remplace import pdb; pdb.set_trace().

Il a également plusieurs nouvelles fonctionnalités , telles que les variables d'environnement possibles.

johnnyheineken
la source
4

Python Tutor est un débogueur en ligne en une seule étape destiné aux novices. Vous pouvez mettre du code sur la page d' édition puis cliquer sur "Visualiser l'exécution" pour le démarrer.

Entre autres, il prend en charge:

Cependant, il ne supporte pas non plus beaucoup de choses , par exemple:

  • Lecture / écriture de fichiers - utilisez io.StringIOet à la io.BytesIOplace: démo
  • Code trop volumineux, trop long ou qui définit trop de variables ou d'objets
  • Arguments de ligne de commande
  • Beaucoup de modules de bibliothèque standard comme argparse, csv, enum, html, os, struct, lowref ...
wjandrea
la source
3

Si vous venez de fond Java / C #, je suppose que votre meilleur pari serait d'utiliser Eclipse avec Pydev . Cela vous donne un IDE entièrement fonctionnel avec un débogueur intégré. Je l'utilise également avec django.

Liorsion
la source
1

Il est également possible de parcourir et de suivre par programme le code Python (et c'est facile!). Consultez la documentation de sys.settrace () pour plus de détails. Voici également un tutoriel pour vous aider à démarrer.

Autocrate
la source
1

PyCharm est un IDE pour Python qui inclut un débogueur. Regardez cette vidéo YouTube pour une introduction sur l'utilisation du débogueur de PyCharm pour parcourir le code.

Tutoriel PyCharm - Déboguer du code python à l'aide de PyCharm

Remarque: ceci n'est pas destiné à être une approbation ou une critique. PyCharm est un produit commercial pour lequel il faut payer, mais la société fournit une licence gratuite aux étudiants et aux enseignants, ainsi qu'une version communautaire «légère», gratuite et open source.

Capture d'écran

Jim
la source
0

Voyons ce que vous breakpoint()pouvez faire pour vous dans la version 3.7+.

J'ai installé ipdb et pdbpp , qui sont tous deux des débogueurs améliorés, via

pip install pdbpp
pip install ipdb

Mon script de test ne fait vraiment pas grand-chose, juste des appels breakpoint().

#test_188_breakpoint.py
myvars=dict(foo="bar")
print("before breakpoint()")
breakpoint()   # 👈
print(f"after breakpoint myvars={myvars}")


breakpoint () est lié à la variable d'environnement PYTHONBREAKPOINT .

CAS 1: désactivation du point d'arrêt ()

Vous pouvez définir la variable via bashcomme d'habitude

export PYTHONBREAKPOINT=0

Cela désactive breakpoint () où il ne fait rien (tant que vous n'avez pas modifié sys.breakpointhook()ce qui est en dehors de la portée de cette réponse).

Voici à quoi ressemble une exécution du programme:

(venv38) myuser@explore$ export PYTHONBREAKPOINT=0
(venv38) myuser@explore$ python test_188_breakpoint.py
before breakpoint()
after breakpoint myvars={'foo': 'bar'}
(venv38) myuser@explore$

Ne s'est pas arrêté, car j'ai désactivé le point d'arrêt. Quelque chose qui pdb.set_trace()ne peut pas faire 😀😀😀!

CAS 2: utilisation du comportement pdb par défaut:

Désactivons maintenant PYTHONBREAKPOINTce qui nous ramène au comportement normal des points d'arrêt activés (il n'est désactivé que lorsqu'il 0n'est pas vide).

(venv38) myuser@explore$ unset PYTHONBREAKPOINT
(venv38) myuser@explore$ python test_188_breakpoint.py
before breakpoint()
[0] > /Users/myuser/kds2/wk/explore/test_188_breakpoint.py(6)<module>()
-> print(f"after breakpoint myvars={myvars}")
(Pdb++) print("pdbpp replaces pdb because it was installed")
pdbpp replaces pdb because it was installed
(Pdb++) c
after breakpoint myvars={'foo': 'bar'}

Il s'est arrêté, mais je l'ai en fait pdbppparce qu'il se remplace pdbentièrement lorsqu'il est installé. Si je décompressais pdbpp, je reviendrais à la normale pdb.

Remarque: une norme pdb.set_trace()m'aurait toujourspdbpp

CAS 3: appeler un débogueur personnalisé

Mais appelons ipdbplutôt. Cette fois, au lieu de définir la variable d'environnement, nous pouvons l'utiliser bashpour la définir uniquement pour cette seule commande.

(venv38) myuser@explore$ PYTHONBREAKPOINT=ipdb.set_trace py test_188_breakpoint.py
before breakpoint()
> /Users/myuser/kds2/wk/explore/test_188_breakpoint.py(6)<module>()
      5 breakpoint()
----> 6 print(f"after breakpoint myvars={myvars}")
      7

ipdb> print("and now I invoked ipdb instead")
and now I invoked ipdb instead
ipdb> c
after breakpoint myvars={'foo': 'bar'}

Essentiellement, ce qu'il fait, quand on regarde $ PYTHONBREAKPOINT:

from ipdb import set_trace  # function imported on the right-most `.`
set_trace()

Encore une fois, beaucoup plus intelligent qu'un vieux pdb.set_trace () 😀😀😀

en pratique? Je me contenterais probablement d'un débogueur.

Dites que je veux toujours ipdb, je le ferais:

  • exportil via .profileou similaire.
  • désactiver commande par commande, sans modifier la valeur normale

Exemple ( pytestet les débogueurs font souvent des couples malheureux):

(venv38) myuser@explore$ export PYTHONBREAKPOINT=ipdb.set_trace
(venv38) myuser@explore$ echo $PYTHONBREAKPOINT
ipdb.set_trace
(venv38) myuser@explore$ PYTHONBREAKPOINT=0 pytest test_188_breakpoint.py
=================================== test session starts ====================================
platform darwin -- Python 3.8.6, pytest-5.1.2, py-1.9.0, pluggy-0.13.1
rootdir: /Users/myuser/kds2/wk/explore
plugins: celery-4.4.7, cov-2.10.0
collected 0 items

================================== no tests ran in 0.03s ===================================
(venv38) myuser@explore$ echo $PYTHONBREAKPOINT
ipdb.set_trace

ps

J'utilise bashunder macos, n'importe quel shell posix se comportera sensiblement de la même manière. Windows, que ce soit PowerShell ou DOS, peut avoir des capacités différentes, en particulier PYTHONBREAKPOINT=<some value> <some command>pour définir une variable d'environnement uniquement pour une commande.

JL Peyret
la source