una tiempo real que matrices lineas graficos graficas graficar funcion dibujar coordenadas con python debugging pycharm breakpoints python-3.4

tiempo - python graficos 2d



Establecer el punto de interrupciĆ³n del depurador al final de una funciĆ³n sin retorno (6)

¿Por qué no dejar el regreso allí? O un return None . Está implícito de todos modos, el intérprete / compilador hará lo mismo independientemente:

De hecho, incluso las funciones sin una declaración de retorno devuelven un valor, aunque bastante aburrido. Este valor se llama Ninguno (es un nombre incorporado).

[fuente: Tutorial de Python 4.6] .

Estoy depurando el método f() que no tiene return .

class A(object): def __init__(self): self.X = [] def f(self): for i in range(10): self.X.append(i)

Necesito ver cómo este método modifica la variable X justo después de que se llama. Para hacer eso, inserto un return al final del método y establezco el punto de interrupción allí:

De esta forma, tan pronto como el método alcanza su return , puedo ver el valor de mi variable X

Esto hace el trabajo, pero estoy bastante seguro de que hay una mejor manera. La edición de un método o función cada vez que necesito depurarlo parece una tontería.

Pregunta :
¿Hay alguna forma diferente (por ejemplo, una opción en el depurador) para establecer un punto de interrupción al final de un método que no tiene return ?

(Tenga en cuenta que establecer un punto de interrupción en la llamada a la función y usar el Paso a paso no mostraría X al pasar el mouse, ya que la función se llama desde un módulo diferente).


Con pdb puedes usar una buena combinación de break function until lineno y until lineno :

Sin argumento, continúe la ejecución hasta que se llegue a la línea con un número mayor que el actual.

Con un número de línea, continúe la ejecución hasta que se alcance una línea con un número mayor o igual a ese. En ambos casos, también se detiene cuando vuelve el marco actual.

Modificado en la versión 3.2: permite dar un número de línea explícito.

Usted puede lograr lo que necesita.

Modifiqué un poco tu ejemplo (para que veas que la instrucción se ejecuta aunque pdb la informe como " siguiente instrucción "):

01: class A(object): 02: 03: def __init__(self): 04: self.X = [] 05: 06: def f(self): 07: print(''pre exec'') 08: for i in range(10): 09: self.X.append(i) 10: print(''post exec'') 11: 12: a = A() 13: a.f() 14: print(''Game is over'') 15:

Y el resultado de correr con python -m pdb test.py es como sigue:

Comience a depurar y ejecútelo justo después de la declaración de clase (para que pueda agregar un punto de interrupción con nombre):

> d:/tmp/stack/test.py(1)<module>() -> class A(object): (Pdb) until 11 > d:/tmp/stack/test.py(12)<module>() -> a = A()

Ahora, rompe al comienzo de la función:

(Pdb) break A.f Breakpoint 1 at d:/tmp/stack/test.py:6

Simplemente continúa con la ejecución hasta que llegue al punto de interrupción:

(Pdb) continue > d:/tmp/stack/test.py(7)f() -> print(''pre exec'')

Aproveche "también detener cuando regrese el marco actual" :

(Pdb) until 14 pre exec post exec --Return--

Como puede ver, se imprimieron tanto el preejecutivo como el posterior al trabajo , pero cuando se ejecuta en where todavía se encuentra en f() :

(Pdb) w c:/python32/lib/bdb.py(405)run() -> exec(cmd, globals, locals) <string>(1)<module>() d:/tmp/stack/test.py(13)<module>() -> a.f() > d:/tmp/stack/test.py(10)f()->None -> print(''post exec'') > d:/tmp/stack/test.py(10)f()->None -> print(''post exec'')

Y todas las variables de contexto están intactas:

(Pdb) p self.X [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Ahora con tu ejemplo de vida real:

01: class A(object): 02: def __init__(self): 03: self.X = [] 04: 05: def f(self): 06: for i in range(10): 07: self.X.append(i) 08: 09: a = A() 10: a.f() 11: print(''Game is over'')

Comience de la misma manera que antes:

> d:/tmp/stack/test.py(1)<module>() -> class A(object): (Pdb) until 8 > d:/tmp/stack/test.py(9)<module>() -> a = A() (Pdb) break A.f Breakpoint 1 at d:/tmp/stack/test.py:5 (Pdb) cont > d:/tmp/stack/test.py(6)f() -> for i in range(10):

Ahora ... Punto de fA en fA en realidad significa un punto de quiebre en la primera declaración de fA que desafortunadamente for i in... por lo que se rompería en cada ocasión.

Si realmente no inicia su código real con bucle, puede omitir esta parte.

(Pdb) disable 1 Disabled breakpoint 1 at d:/tmp/stack/test.py:5

Nuevamente, use until <end of file> :

(Pdb) until 10 --Return-- > d:/tmp/stack/test.py(6)f()->None -> for i in range(10):

Y de nuevo, todas las variables de cuadro están disponibles:

(Pdb) p i 9 (Pdb) w c:/python32/lib/bdb.py(405)run() -> exec(cmd, globals, locals) <string>(1)<module>() d:/tmp/stack/test.py(10)<module>() -> a.f() > d:/tmp/stack/test.py(6)f()->None -> for i in range(10): (Pdb)

Lo triste aquí es que quería probar esta pieza de automatización:

(Pdb) break A.f Breakpoint 1 at d:/tmp/stack/test.py:5 (Pdb) commands 1 (com) disable 1 (com) until 11 (com) end

Que haría todo lo que necesita automáticamente (de nuevo, disable 1 no es necesario cuando tiene al menos una instrucción de ciclo previo), pero de acuerdo con la documentación de los commands :

Al especificar cualquier comando que reanude la ejecución (actualmente continúa, paso, siguiente, retorno, salto, abandono y sus abreviaturas) finaliza la lista de comandos (como si ese comando fuera seguido inmediatamente por el final). Esto se debe a que cada vez que reanuda la ejecución (incluso con un simple siguiente o paso), puede encontrar otro punto de interrupción, que podría tener su propia lista de comandos, lo que generaría ambigüedades sobre qué lista ejecutar.

Hasta que parece que no funciona (al menos para Python 3.2.5 en Windows) y tienes que hacer esto a mano.


Hay una solución rápida y sucia que funciona en cualquier idioma que admita monopatching (Python, Ruby, ObjC, etc.). Honestamente, no recuerdo haberlo necesitado alguna vez en Python, pero lo hice bastante en SmallTalk y ObjC, así que tal vez te sea útil.

Simplemente envuelva dinámicamente Af en una función, como esta:

real_A_f = A.f def wrap_A_f(self, *args, **kwargs): result = real_A_f(self, *args, **kwargs) return result A.f = wrap_A_f

En la mayoría de los depuradores de secuencias de comandos, debe poder escribir un script que lo haga automáticamente para un método por nombre. En pdb, que te permite ejecutar código Python normal directamente en el depurador, es especialmente simple.

Ahora puede poner un punto de inflexión en ese return result , y se garantiza que golpeará inmediatamente después de los retornos reales de Af (incluso si vuelve a la mitad o cae al final sin una declaración de return ).

Algunas cosas que quizás quiera agregar:

  • Si también desea capturar Af , try: y except: raise el código y agregar un punto de interrupción en el raise .
  • Para Python 2.x, es posible que desee envolverlo con types.MethodType para hacer un método unbound real.
  • Si solo desea un punto de interrupción en una instancia A específica, puede usar un punto de corte condicional que compruebe que self is a , o use types.MethodType para crear una instancia enlazada y almacenarla como af .
  • Es posible que desee utilizar functools.wraps si desea ocultar el contenedor del resto del código (y de la depuración, excepto en los casos en los que realmente desea verlo).
  • Dado que pdb le permite ejecutar código dinámico directamente en el espacio de nombres en vivo, puede poner una función wrap_method en algún lugar de su proyecto que haga esto, y luego, en el prompt, escriba p utils.wrap_method(A, ''f'') . Pero si ajusta varios métodos de esta manera, compartirán los mismos puntos de interrupción (dentro de la función de envoltura definida dentro de wrap_method ). Aquí creo que un punto de corte condicional es la única opción razonable.
  • Si quieres acceder a los lugareños reales de Af desde el punto de interrupción del contenedor, eso es mucho más difícil. Puedo pensar en algunas opciones muy hacky (por ejemplo, exec(real_A_f.__code__, real_A_f.globals()) , pero nada con lo que estaría contento.

Puede agregar un punto de interrupción condicional en la última línea y configurar la condición para que sea algo que ocurra solo en la última iteración.

En este caso, la condición es muy fácil ya que es solo i == 9 , pero puede ser mucho más compleja dependiendo de la condición del ciclo, por lo que a veces agregar una instrucción al final será la solución más fácil.

Esa captura de pantalla es de IntelliJ IDEA y parece que su captura de pantalla es del mismo IDE, por lo que simplemente haga clic con el botón derecho en el punto de interrupción para mostrar el cuadro de diálogo e ingresar su condición.

Si está utilizando algún otro IDE, estoy seguro de que hay capacidad para hacer un punto de corte condicional.

Actualizar:

No hay soporte para romper al final de un método en el depurador de Python , solo al comienzo de un método:

b (reak) [[nombre de archivo:] lineno | función [, condición]]

Con un argumento de Lineno, establezca un corte en el archivo actual. Con un argumento de función, establezca un corte en la primera instrucción ejecutable dentro de esa función. El número de línea puede tener un prefijo con un nombre de archivo y dos puntos, para especificar un punto de interrupción en otro archivo (probablemente uno que aún no se haya cargado). El archivo se busca en sys.path. Tenga en cuenta que a cada punto de interrupción se le asigna un número al que hacen referencia todos los demás comandos de punto de interrupción.

Si hay un segundo argumento presente, es una expresión que debe evaluarse como verdadera antes de que se respete el punto de interrupción.

Sin argumentos, enumere todos los saltos, incluso para cada punto de interrupción, la cantidad de veces que se ha alcanzado ese punto de interrupción, el recuento de ignorar actual y la condición asociada, si la hay.


Tienes algunas opciones aquí.

  1. Agregue un punto de interrupción a la última línea de la función.

En este caso, la última línea está dentro de un bucle, por lo que tendría que iterar sobre cada elemento en el bucle.

  1. Agregue un punto de corte donde se llama a la función.

Esto detendrá el depurador antes de llamar a la función, pero puede "pasar por encima" de la función para ver el valor de Ax después de llamar a Af() .

  1. Agregue una declaración temporal al final de la función para romper en

Este truco funcionaría si su función termina en un bucle y hay múltiples lugares donde se llama a la función o si no desea rastrear la llamada a la función.

Puede agregar una instrucción simple al final de la función para fines de depuración y agregar un punto de interrupción allí.

def f(self): for i in range(10): self.X.append(i) debug_break = 1


Tu IDE está ocultando lo que hay debajo del capó. Es decir, algo así como

import pdb

se antepone a su secuencia de comandos y

pdb.set_trace()

se inserta antes de la línea en la que colocaste tu punto de interrupción. Por lo que dices, deduzco que a PyCharm no le gusta colocar puntos de interrupción en líneas vacías. Sin embargo, pdb.set_trace() puede colocarse perfectamente al final de un método.

De modo que podría insertarlos usted mismo (o escribir una macro) y ejecutar python -m pdb para iniciar la depuración.

(Editar) ejemplo

import pdb class A(object): def __init__(self): self.X = [] def f(self): for i in range(10): self.X.append(i) pdb.set_trace() if __name__ == ''__main__'': a = A() a.f()

Depurar con

$ python -m pdb test.py > /dev/test.py(1)<module>() ----> 1 import pdb 2 3 class A(object): ipdb> cont --Return-- > /dev/test.py(11)f()->None -> pdb.set_trace() (Pdb) self.X [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] (Pdb)

ipdb se puede usar en lugar de pdb .