2011-10-05 18 views
36

Estoy depurando una secuencia de comandos python, y quiero ver una variable para un cambio (como puede ver una dirección de memoria en gdb). ¿Hay alguna forma de hacer esto?Cómo observa una variable en pdb

+0

Puede hacer esto en [pudb] (https://pypi.python.org/pypi/pudb) –

+0

@WayneWerner ¿desea agregar una respuesta que muestre esto o vincule a los documentos? Estoy buscando explícitamente cómo hacer esto en 'pudb' pero quedando vacío ... –

+0

@JeffWidman Esa sería otra pregunta, házmelo saber cuando lo preguntes :) –

Respuesta

22

Aquí hay una manera realmente hacky de hacer esto con pdb. Estos comandos se pueden poner en su ~/.pdbrc para la carga automática cada vez que usa 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"]) 

Esto añade dos comandos, nextwatch y stepwatch la que cada uno tome un nombre de variable nombre_var como argumento. Harán una copia superficial de la variable local del marco actual para varname si es posible, y seguirán ejecutando next o step respectivamente hasta que cambie el nombre.

Esto funciona en CPython 2.7.2 pero depende de algunos internos pdb por lo que probablemente se rompa en otro lugar.

+0

Copié las macros en mi archivo ~/.pdbrc. Sin embargo, pdb me dice: NameError 'nextwatch' no está definido. I Fall it this: "nextwatch" (var) –

+0

Uso python 3.5, mac, y parece que '.pdbrc' no funciona. Incluso cuando pego el código de arriba en el entorno' (pdb): ', cuando ejecuta 'stepwatch' o' nextwatch', dice '__dict' y otros no están definidos. ¿Podrías actualizar tu código para Python 3.5? Gracias – Daniel

+0

Como se mencionó, probablemente esto no funcione en algunas otras versiones de Python. publicar una versión de Python 3.5 como una nueva respuesta. –

16

Para ver una variable cuando está llegando a un breakpoint, puede usar el comando commands. P.ej. imprimiendo some_variable al llegar al punto de ruptura n. ° 1 (canonical example from pdb doc).

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

Esta debería ser la respuesta principal. Fácil, directo, le enseña una característica clara de pdb: los comandos de punto de interrupción –

+1

Si bien puede ser útil, no responde directamente la pregunta , que desea observar los cambios en las variables y luego romper esos cambios, no solo ver el estado de una variable en los puntos de corte preestablecidos. – kmantel

8

Para Python 3:

puede utilizar display funcionalidad de AP

Una vez que llegue al punto de interrupción sólo tiene que escribir

IPDB>pantallaexpresión

ejemplo:

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> 

como se puede ver, cada vez que escriba pantalla - se imprimirá todas sus relojes (expresiones). Puede usar la función de visualización para eliminar cierto reloj.

También puede utilizar expresión pp a prettyprint la expresión (muy útil)

6

Una posible solución es utilizar pdb++:

pip install pdbpp 

Entonces "marca" el objeto que desea ver con el decorador @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 

Aquí pdb Wil Interrumpir cualquier cambio del atributo bar en cualquier Foo-objeto.

Advertencias
Sólo invocaciones del __setattr__ -method subyacente activará el punto de interrupción.Esto significa que f.bar = 'XYZ' y setattr(f, 'XYZ') va a funcionar, pero la manipulación de la -objeto bar no activará el punto de interrupción:

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

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

Nota: @break_on_setattr no es parte de la pdb-módulo estándar. pdb es anulado/revisado por el paquete pdbpp.