web-dev-qa-db-fra.com

Comment regardez-vous une variable dans pdb

Je débogue un script python, et je veux regarder une variable pour un changement (un peu comme vous pouvez regarder une adresse mémoire dans gdb). Existe-t-il un moyen de le faire?

53
Nathaniel Flath

Pour regarder une variable lorsque vous atteignez un point d'arrêt , vous pouvez utiliser la commande commands. Par exemple. impression some_variable lorsque vous atteignez le point d'arrêt # 1 ( exemple canonique de pdb doc ).

(Pdb) commands 1
(com) print some_variable
(com) end
(Pdb)

Mise à jour pour Python 3

(Pdb) commands 1
(com) print(some_variable)
(com) end
(Pdb)

De plus, vous pouvez utiliser la commande condition pour vous assurer que le point d'arrêt n'est atteint que lorsque la variable prend une certaine valeur.

par exemple:

(Pdb) condition 1 some_variable==some_value
23
dnozay

Voici une façon vraiment hacky de le faire avec pdb. Ces commandes peuvent être placées dans votre ~/.pdbrc pour un chargement automatique à chaque fois que vous utilisez pdb.

!global __currentframe, __stack; from inspect import currentframe as __currentframe, stack as __stack
!global __copy; from copy import copy as __copy
!global __Pdb; from pdb import Pdb as __Pdb
!global __pdb; __pdb = [__framerec[0].f_locals.get("pdb") or __framerec[0].f_locals.get("self") for __framerec in __stack() if (__framerec[0].f_locals.get("pdb") or __framerec[0].f_locals.get("self")).__class__ == __Pdb][-1]

alias _setup_watchpoint !global __key, __dict, __val; __key = '%1'; __dict = __currentframe().f_locals if __currentframe().f_locals.has_key(__key) else __currentframe().f_globals; __val = __copy(%1)

alias _nextwatch_internal next;; !if __dict[__key] == __val: __pdb.cmdqueue.append("_nextwatch_internal %1")
alias _stepwatch_internal step;; !if __dict[__key] == __val: __pdb.cmdqueue.append("_stepwatch_internal %1")

alias nextwatch __pdb.cmdqueue.extend(["_setup_watchpoint %1", "_nextwatch_internal"])
alias stepwatch __pdb.cmdqueue.extend(["_setup_watchpoint %1", "_stepwatch_internal"])

Cela ajoute deux commandes, nextwatch et stepwatch qui prennent chacune un nom de variable varname comme argument. Ils feront une copie superficielle de la variable locale du cadre actuel pour varname si possible, et continueront d'exécuter next ou step respectivement jusqu'à ce que ce nom pointe vers des changements.

Cela fonctionne dans CPython 2.7.2 mais repose sur quelques pdb internes donc il se cassera probablement ailleurs.

22
Michael Hoffman

Pour Python 3 :

vous pouvez utiliser display la fonctionnalité de pdb

Une fois que vous avez atteint le point d'arrêt, tapez simplement

ipdb> affichage expression

exemple:

ipdb> display instance
display instance: <AppUser: dmitry4>
ipdb> display instance.id
display instance.id: 9
ipdb> display instance.university
display instance.university: <University: @domain.com>

ipdb> display

Currently displaying:
instance.university: <University: @domain.com>
instance.id: 9
instance: <AppUser: dmitry4>
ipdb> 

comme vous pouvez le voir, chaque fois que vous tapez display, il imprime toutes vos montres (expressions). Vous pouvez utiliser la fonction intégrée undisplay pour supprimer certaines montres.

Vous pouvez également utiliser l'expression pp pour joliment imprimer l'expression (très utile)

15
DmitrySemenov

Une solution possible consiste à utiliser pdb ++ :

pip install pdbpp

Ensuite, "marquez" l'objet que vous souhaitez regarder avec le décorateur @pdb.break_on_setattr:

from pdb import break_on_setattr
@break_on_setattr('bar')
class Foo(object):
    pass

f = Foo()
f.bar = 42    # the program breaks here

Ici, pdb se cassera lors de tout changement de l'attribut bar sur n'importe quel objet Foo.

Mises en garde
Seules les invocations de la méthode __setattr__ Sous-jacente déclencheront le point d'arrêt. Cela signifie que f.bar = 'XYZ' Et setattr(f, 'XYZ') fonctionneront, mais la manipulation de l'objet bar - ne déclenchera pas le point d'arrêt:

f.bar = []
f.bar.append(7) # will NOT trigger breakpoint

f.bar = 2
f.bar += 5      # will trigger breakpoint

Remarque: @break_on_setattr Ne fait pas partie du module pdb standard. pdb est remplacé/patché par le singe par le package pdbpp.

Vous pouvez également envelopper un objet existant (via sa classe) après pdb.set_trace():

(Pdb++) import pdb
(Pdb++) pdb.break_on_setattr('tree_id')(self.__class__)
(Pdb++) continue
13
qff