web-dev-qa-db-fra.com

Comment savoir où se trouve mon script python?

Je suis donc en train de déboguer mon programme python et j'ai rencontré un bogue qui le bloque, comme dans une boucle infinie. Auparavant, j'avais déjà eu un problème avec une boucle infinie auparavant, mais quand il a raccroché, je pouvais tuer le programme et python a généré une exception utile qui m'indiquait où le programme s'était terminé lorsque je lui avais envoyé la commande kill. Maintenant, cependant, quand le programme raccroche et que je le ctrl-c, il n’abandonne pas mais continue de fonctionner. Existe-t-il un outil que je peux utiliser pour localiser le blocage? Je suis novice en profilage, mais d'après ce que je sais, un profileur peut uniquement vous fournir des informations sur un programme qui s'est terminé avec succès. Ou pouvez-vous utiliser un profileur pour déboguer de tels problèmes?

42
Johnny

Supposons que vous exécutez votre programme en tant que:

python YOURSCRIPT.py

Essayez d’exécuter votre programme en tant que:

python -m trace --trace YOURSCRIPT.py

Et avoir un peu de patience pendant que beaucoup de choses sont imprimées à l'écran. Si vous avez une boucle infinie, elle continuera à jamais (problème d’arrêt). Si elle se coince quelque part, vous êtes généralement bloqué sur les E/S ou vous vous retrouvez dans une impasse.

83
dhruvbird

Hou la la! 5 réponses déjà et personne n'a suggéré le plus évident et simple:

  1. Essayez de trouver un scénario de test reproductible qui entraîne le problème du blocage.
  2. Ajoutez l'enregistrement à votre code. Cela peut être aussi élémentaire que print "**010", print "**020", etc. parsemé de zones principales.
  3. Exécuter le code. Voir où il se bloque. Vous ne pouvez pas comprendre pourquoi? Ajouter plus de journalisation. (C.-à-d. Si entre ** 020 et ** 030, ajoutez ** 023, ** 025, ** 027, etc.)
  4. Aller à 3.

Les enfants de nos jours avec leurs débogueurs et IDE sophistiqués ... Parfois, les problèmes d'ingénierie sont résolus plus simplement avec des outils rudimentaires qui fournissent juste un peu plus d'informations.

24
dkamins

Si votre programme est trop volumineux et complexe pour être viable pour un pas à pas avec pdb ou pour imprimer chaque ligne avec le module de suivi, vous pouvez essayer une astuce de ma période de programmation de jeux 8 bits. À partir de Python 2.5, pdb peut associer du code à un point d'arrêt à l'aide de la commande commands. Vous pouvez utiliser ceci pour imprimer un message et continuer à courir:

(Pdb) commands 1
(com) print "*** Breakpoint 1 ***"
(com) continue
(com) end
(Pdb)

Ceci imprimera un message et continuera à s'exécuter lorsque le point d'arrêt 1 sera atteint. Définissez des commandes similaires pour quelques autres points d'arrêt. 

Vous pouvez l'utiliser pour effectuer une sorte de recherche binaire de votre code. Attachez des points d'arrêt aux endroits clés du code et exécutez-le jusqu'à ce qu'il se bloque. Vous pouvez dire à partir du dernier message quel était le dernier point d'arrêt touché. Vous pouvez ensuite déplacer les autres points d'arrêt et recommencer pour réduire l'endroit dans le code où il se bloque. Rincer et répéter.

Incidemment, sur les micros 8 bits (Commodore 64, Spectrum, etc.), vous pouvez insérer une valeur dans un emplacement du registre pour modifier la couleur de la bordure autour de l'écran. J'avais l'habitude de configurer quelques points d'arrêt pour le faire avec différentes couleurs. Ainsi, lorsque le programme était lancé, il affichait un affichage psychédélique de Rainbow jusqu'à ce qu'il soit suspendu. La bordure devenait alors une couleur unique qui indiquait le dernier point d'arrêt. Vous pouvez également avoir une bonne idée de la performance relative des différentes sections de code en fonction de la quantité de chaque couleur dans l'arc-en-ciel. Parfois, cette simplicité me manque dans ces nouvelles machines "Windows".

9
Dave Kirby

J'ai écrit un module qui imprime les fils qui durent plus longtemps que 10 secondes à un endroit . accrocher_threads.py

Voici un exemple de sortie:

--------------------    Thread 5588     --------------------
  File "C:\python33\lib\threading.py", line 844, in _exitfunc
        t.join()
  File "C:\python33\lib\threading.py", line 743, in join
        self._block.wait()
  File "C:\python33\lib\threading.py", line 184, in wait
        waiter.acquire()

Cela se produit à la sortie du thread principal lorsque vous oubliez de définir un autre thread en tant que démon.

7
User

Il est plus facile d'éviter ces blocages que de les déboguer.

Premièrement: les boucles for sont très, très difficiles à bloquer dans une situation où la boucle ne se termine pas. Très dur. 

Deuxièmement: les boucles while sont relativement faciles à rester coincées dans une boucle.

La première étape consiste à vérifier chaque boucle while pour voir s’il s’agit doit _ être une boucle while. Souvent, vous pouvez remplacer les constructions while par for et vous corrigerez votre problème en repensant votre boucle.

Si vous ne pouvez pas remplacer une boucle while par for, vous devez simplement prouver que l'expression de l'instruction whiledoit _ change à chaque fois dans la boucle. Ce n'est pas si difficile à prouver.

  1. Regardez toutes les conditions de la boucle. Appelez ceci T.

  2. Regardez toutes les branches logiques dans le corps de la boucle. Existe-t-il un moyen de parcourir la boucle sans modifier la condition T

    • Oui? C'est ton bug. Ce chemin logique est faux.

    • Non? Excellent, cette boucle doit se terminer. 

3
S.Lott

Si votre programme est un peu trop complexe pour tracer simplement toutes les fonctions, vous pouvez essayer de l'exécuter et d'y attacher manuellement un programme de suivi tel que lptrace . Cela fonctionne un peu comme strace– il imprime toutes les fonctions appelées par votre programme. Voici comment l'appeler:

python lptrace -p $STUCK_PROGRAM_PID

Notez que lptrace nécessite gdb pour s'exécuter.

2
Karim H

Vous pouvez également essayer http://code.activestate.com/recipes/576515-debugging-a-running-python-process-by-interrupting/ . Cela devrait fonctionner tant que le processus Python n'a pas de signaux masqués, ce qui est normalement le cas même si Ctrl-C ne fonctionne pas.

1
Daira Hopwood

Rien de tel que le bon vieux pdb

import pdb
pdb.run('my_method()',globals(),locals())

Ensuite, appuyez simplement sur (n) pour passer à la commande suivante, dans laquelle vous devez entrer. voir la documentation pour la référence complète . Suivez votre programme étape par étape, et vous l'aurez compris assez rapidement.

1
Ofri Raviv
i = 0
for t in threading.enumerate():
    if i != 0:# and t.getName() != 'Thread-1':
        print t.getName()
        t._Thread__stop()
    i += 1

Une fois que vous connaissez les noms des discussions; commencez à ré-exécuter votre script et filtrez-les pour ne pas les empêcher d'être abandonnés. i = 0 conditionnel empêche le thread principal d'être abandonné.

Je suggère de passer en revue et de nommer toutes vos discussions; tels que: Thread (target = self.log_sequence_status, name = 'log status')

Ce code doit être placé à la fin du programme principal qui lance le processus de fuite.

0
Justin Catterson

Je ne l'ai pas utilisé moi-même, mais j'ai entendu dire que le Eric IDE est bon et qu'il a un bon débogueur. C’est aussi le seul IDE que je connaisse qui ait un débogueur pour Python

0
Matti Lyra

Si votre programme a plus d'un thread, il est possible que ctrl-c soit ignoré, car l'un des threads est connecté au gestionnaire ctrl-c, mais le thread live (emballé?) En est sourd. Le verrou global d'interprète (GIL) dans CPython signifie que normalement, un seul thread ne peut être exécuté à la fois… .. Je pense avoir résolu mon problème similaire (peut-être) en utilisant this

0
phlip