Categorías
Python

Frasco por Ejemplo – Actualización del entorno de ensayo

 

Tabla de Contenidos

  • Introducción: Impresión de Valor
  • impresión Expresiones
  • Stepping de una variable a través de Código Fuente CodeListing
  • Listado de Código Fuente
  • con puntos de parada
  • Continua ejecución
  • Viendo Expresiones
  • Python Caller ID
  • esencial AP Comandos
  • Python Depuración con pdb: Conclusión
  • Código Fuente de venta

Mira ahora Este tutorial tiene un vídeo relacionado curso creado por el equipo del real Python. Mira que junto con el tutorial escrito para profundizar su comprensión: aplicaciones Python Depuración con pdb

depuración a veces puede ser una actividad no deseada. Estás ocupado trabajando bajo una presión de tiempo y lo que desea que funcione. Sin embargo, en otras ocasiones, es posible que se aprende una nueva característica del lenguaje o experimentar con un nuevo enfoque y quiere entender más profundamente cómo algo está funcionando.

Independientemente de la situación, la depuración del código es una necesidad, por lo que es una buena idea estar cómodo trabajando en un depurador. En este tutorial, te voy a mostrar los aspectos básicos del uso pdb, interactiva código fuente depurador de Python.

me voy a caminar a través de algunos de los usos comunes de AP. Es posible que desee marcar este tutorial para una referencia rápida más tarde cuando realmente lo necesite. AP y otros depuradores, son herramientas indispensables. Cuando se necesita un depurador, no hay sustituto. Realmente lo necesita.

Al final de este tutorial, usted sabrá cómo utilizar el depurador para ver el estado de cualquier variable en su aplicación. También será capaz de detener y reanudar el flujo de la aplicación la ejecución en cualquier momento, para que pueda ver exactamente cómo cada línea de código afecta a su estado interno.

Esto es grande para rastrear errores difíciles de encontrar y le permite fijar el código defectuoso más rápida y fiable. A veces, dando un paso a través del código de PDB y ver cómo cambian los valores puede ser una verdadera revelación y dar lugar a “aha” momentos, junto con el ocasional “palma de la cara”.

AP es parte de la biblioteca estándar de Python, por lo que siempre existe y está disponible para su uso. Esto puede ser un salvavidas si es necesario depurar el código en un entorno en el que no tiene acceso a la interfaz gráfica de usuario depurador está familiarizado con.

El código de ejemplo en este tutorial usa Python 3.6. Puede encontrar el código fuente de estos ejemplos en GitHub.

Al final de este tutorial, hay una referencia rápida para los comandos pdb Esenciales.

También hay un AP imprimible Referencia de comandos se puede utilizar como una hoja de trucos durante la depuración: Bonus

gratuito: Haga clic aquí para obtener una impresión «pdb mandatos» (PDF) que se puede mantener en su escritorio y se refieren a durante la depuración.

Introducción: La impresión de una variable de valor

En este primer ejemplo, vamos a ver el uso de AP en su forma más simple: la comprobación del valor de una variable.

Inserte el siguiente código en el lugar donde desea interrumpir el depurador:

import pdb; pdb.set_trace()

Cuando se ejecuta la línea anterior, Python se detiene y espera a que se diga qué hacer a continuación. Usted verá un indicador (PDB). Esto significa que usted ahora está en pausa en el depurador interactivo y puede introducir un comando.

A partir de Python 3.7, hay otra manera de entrar en el depurador. PEP 553 describe el punto de interrupción función incorporada (), lo que hace entrar en el depurador fácil y consistente:

breakpoint()

Por defecto, punto de interrupción () importará pdb y pdb.set_trace llamada (), como se muestra arriba. Sin embargo, el uso de punto de interrupción () es más flexible y permite controlar el comportamiento de depuración a través de su API y el uso de la variable de entorno PYTHONBREAKPOINT. Por ejemplo, establecer PYTHONBREAKPOINT = 0 en su entorno se deshabilitar completamente el punto de interrupción (), por lo tanto desactivar la depuración. Si está utilizando Python 3.7 o posterior, le animo a utilizar punto de interrupción () en lugar de pdb.set_trace ().

También puede interrumpir el depurador, sin modificar la fuente y el uso de pdb.set_trace () o punto de interrupción (), mediante la ejecución de Python directamente desde la línea de comandos y pasar el AP opción -m. Si su aplicación acepta los argumentos de línea de comandos, pasarlas como lo haría normalmente después de que el nombre de archivo. Por ejemplo:

$ python3 -m pdb app.py arg1 arg2

Hay una gran cantidad de AP comandos disponibles. Al final de este tutorial, hay una lista de comandos pdb Esenciales. Por ahora, vamos a usar el comando p para imprimir el valor de una variable. Ingrese p variable_name en la (PDB) del sistema para imprimir su valor. La mirada de

Veamos el ejemplo. Aquí está la fuente example1.py:

#!/usr/bin/env python3

filename = __file__
import pdb; pdb.set_trace()
print(f'path = {filename}')

Si ejecuta esta información de su concha, que debe obtener el siguiente resultado:

$ ./example1.py
> /code/example1.py(5)()
-> print(f'path = {filename}')
(Pdb)

Si usted está teniendo problemas para conseguir los ejemplos o su propio código para ejecutar desde la línea de comandos, leer cómo Cómo puedo hacer mi propia línea de comandos de comandos usando Python? Si estás en Windows, compruebe el pitón de Windows FAQ.

Ahora ingrese p nombre de archivo. Debería ver:

(Pdb) p filename
'./example1.py'
(Pdb)

Ya que estás en una cáscara y utilizando una CLI (interfaz de línea de comandos), prestar atención a los caracteres y el formato. Ellos le dan el contexto que necesita:

  • > comienza la primera línea y qué archivo de fuente que está en el nombre del archivo le dice Después, está el número de línea actual entre paréntesis.. El siguiente es el nombre de la función. En este ejemplo, ya que no estamos pausa dentro de una función y al nivel de módulo, vemos ().
  • -> se inicia la segunda línea y es la fuente de corriente de línea en el que se detuvo Python. Esta línea no se ha ejecutado todavía. En este ejemplo, esta es la línea 5 en example1.py, desde la línea de > anteriormente.
  • (PDB) es de pronta AP. Está a la espera de un comando.

Utilice el comando q para salir de depuración y de salida.

impresión Expresiones

Cuando se utiliza el comando de impresión P, estás pasando una expresión para ser evaluada por Python. Si pasa un nombre de variable, PDB imprime su valor actual. Sin embargo, se puede hacer mucho más para investigar el estado de su aplicación en ejecución.

En este ejemplo, el get_path función () se llama. Para inspeccionar lo que está sucediendo en esta función, he insertado una llamada a pdb.set_trace () para detener la ejecución justo antes de que vuelva:

#!/usr/bin/env python3

import os

def get_path(filename):
"""Return file's path or empty string if no path."""
head, tail = os.path.split(filename)
import pdb; pdb.set_trace()
return head

filename = __file__
print(f'path = {get_path(filename)}')

Si ejecuta esta información de su cáscara, usted debe obtener la salida:

$ ./example2.py
> /code/example2.py(10)get_path()
-> return head
(Pdb)

Dónde están ¿nosotros?

  • >: Estamos en el example2.py archivo de origen en la línea 10 en el get_path función (). Este es el marco de referencia el comando p utilizará para resolver nombres de variables, es decir, el alcance o contexto actual.
  • ->: La ejecución se ha detenido a la cabeza de retorno. Esta línea no se ha ejecutado todavía. Esta es la línea 10 en example2.py en el get_path función (), desde la línea de > anteriormente. impresión de

Let algunas expresiones que mira el estado actual de la aplicación. Yo uso el comando ll (longlist) inicialmente a la lista de fuentes de la función:

(Pdb) ll
6 def get_path(filename):
7 """Return file's path or empty string if no path."""
8 head, tail = os.path.split(filename)
9 import pdb; pdb.set_trace()
10 -> return head
(Pdb) p filename
'./example2.py'
(Pdb) p head, tail
('.', 'example2.py')
(Pdb) p 'filename: ' + filename
'filename: ./example2.py'
(Pdb) p get_path

(Pdb) p getattr(get_path, '__doc__')
"Return file's path or empty string if no path."
(Pdb) p [os.path.split(p)[1] for p in os.path.sys.path]
['pdb-basics', 'python36.zip', 'python3.6', 'lib-dynload', 'site-packages']
(Pdb)

Puede pasar cualquier expresión válida en Python ap para su evaluación.

Esto es especialmente útil cuando se está depurando y desea probar una implementación alternativa directamente en la aplicación en tiempo de ejecución.

También puede utilizar el comando pp (bastante-impresión) a expresiones bastante impresos. Esto es útil si desea imprimir una variable o expresión con una gran cantidad de producción, por ejemplo, listas y diccionarios. impresión bastante-guarda objetos en una sola línea si se puede o se rompe ellos en varias líneas si no cabe dentro de la anchura permitida.

recorrer el código

Hay dos comandos que puede utilizar para desplazarse por el código durante la depuración:

Hay una tercera comando denominado UNT (hasta). Se relaciona con n (siguiente). Vamos a ver más adelante en este tutorial en la sección Ejecución Continua.

La diferencia entre n (siguiente) y s (etapa) es donde se detiene pdb.

Uso n (siguiente) para continuar la ejecución hasta la siguiente línea y permanecer dentro de la función actual, no es decir detener en una función extranjera si uno se llama. Pensar en el próximo como “permanecer locales” o “pasar por encima”.

Uso s (paso) para ejecutar la línea y parada actual en una función extranjera si uno se llama. Pensar en el paso de “recorrer”. Si la ejecución se detiene en otra función, s se imprimirán –Call–.

ambos N y s dejarán de ejecución cuando se llega al final de la función actual e imprimir –Return– junto con el valor de retorno al final de la siguiente línea después ->. La mirada de

Veamos un ejemplo usando ambos comandos. Aquí está la fuente example3.py:

#!/usr/bin/env python3

import os

def get_path(filename):
"""Return file's path or empty string if no path."""
head, tail = os.path.split(filename)
return head

filename = __file__
import pdb; pdb.set_trace()
filename_path = get_path(filename)
print(f'path = {filename_path}')

Si ejecuta esta información de su concha y entra n, usted debe obtener la salida:

$ ./example3.py
> /code/example3.py(14)()
-> filename_path = get_path(filename)
(Pdb) n
> /code/example3.py(15)()
-> print(f'path = {filename_path}')
(Pdb)

Con n (al lado), paramos en la línea 15, la línea siguiente. Nos “quedamos local” () y “pasó por encima” de la llamada a get_path (). La función es () ya que estamos actualmente en el nivel de módulo y no una pausa dentro de otra función. try de

Let s:

$ ./example3.py
> /code/example3.py(14)()
-> filename_path = get_path(filename)
(Pdb) s
--Call--
> /code/example3.py(6)get_path()
-> def get_path(filename):
(Pdb)

Con s (paso), que se detuvo en la línea 6 en el get_path función (), ya que fue llamado en la línea 14. Observe la línea –Call– después del comando s.

Convenientemente, PDB recuerda su última orden. Si usted está pasando a través de una gran cantidad de código, puede simplemente pulse la tecla Intro para repetir el último comando.

continuación se muestra un ejemplo del uso de ambos s y n a paso a través del código. Entro s inicialmente porque quiero “paso en” la get_path () y stop. Entonces entro n una vez para “permanecer locales” o “pasar por encima” de cualquier otra llamada de función y pulse Enter para simplemente repetir el comando n hasta que llegue a la última línea de código fuente.

$ ./example3.py
> /code/example3.py(14)()
-> filename_path = get_path(filename)
(Pdb) s
--Call--
> /code/example3.py(6)get_path()
-> def get_path(filename):
(Pdb) n
> /code/example3.py(8)get_path()
-> head, tail = os.path.split(filename)
(Pdb)
> /code/example3.py(9)get_path()
-> return head
(Pdb)
--Return--
> /code/example3.py(9)get_path()->'.'
-> return head
(Pdb)
> /code/example3.py(15)()
-> print(f'path = {filename_path}')
(Pdb)
path = .
--Return--
> /code/example3.py(15)()->None
-> print(f'path = {filename_path}')
(Pdb)

Tenga en cuenta las líneas –Call– y –Return–. Esta es pdb que le permite saber qué se interrumpió la ejecución. n (siguiente) y s (etapa) se detendrá antes de una función devoluciones. Es por eso que ves las líneas –Return– anteriores.

También tenga en cuenta -> » al final de la línea después de los primeros –Return– anteriores:

--Return--
> /code/example3.py(9)get_path()->'.'
-> return head
(Pdb)

Cuando AP se detiene al final de una función antes de que vuelva, que también imprime el valor de retorno para usted. En este ejemplo es ».

Listado de Código Fuente

no se olvide el comando ll (longlist: lista de todo el código fuente de la función o el cuadro actual). Es muy útil cuando se está dando un paso a través del código desconocido o lo que desea es ver toda la función de contexto.

He aquí un ejemplo:

$ ./example3.py
> /code/example3.py(14)()
-> filename_path = get_path(filename)
(Pdb) s
--Call--
> /code/example3.py(6)get_path()
-> def get_path(filename):
(Pdb) ll
6 -> def get_path(filename):
7 """Return file's path or empty string if no path."""
8 head, tail = os.path.split(filename)
9 return head
(Pdb)

Para ver un fragmento más corto de código, utilice el comando l (lista). Sin argumentos, se imprimirá 11 líneas alrededor de la línea actual o continuar la lista anterior. Pasar el argumento. siempre a una lista de 11 líneas alrededor de la línea actual: l.

$ ./example3.py
> /code/example3.py(14)()
-> filename_path = get_path(filename)
(Pdb) l
9 return head
10
11
12 filename = __file__
13 import pdb; pdb.set_trace()
14 -> filename_path = get_path(filename)
15 print(f'path = {filename_path}')
[EOF]
(Pdb) l
[EOF]
(Pdb) l .
9 return head
10
11
12 filename = __file__
13 import pdb; pdb.set_trace()
14 -> filename_path = get_path(filename)
15 print(f'path = {filename_path}')
[EOF]
(Pdb)

con puntos de parada

puntos de interrupción son muy convenientes y se puede ahorrar mucho tiempo. En lugar de dar un paso a través de las líneas que no le interesa, basta con crear un punto de interrupción en la que desea investigar decenas. Opcionalmente, también se puede decir pdb para romper sólo cuando una determinada condición es verdadera.

Utilice el comando B (rotura) para establecer un punto de interrupción. Se puede especificar un número de línea o un nombre de función en la que se detiene la ejecución.

La sintaxis de ruptura es:

b(reak) [ ([filename:]lineno | function) [, condition] ]

Si el nombre de archivo: no se ha especificado antes de la lineno número de línea, el archivo fuente de corriente se utiliza. Nota

el segundo argumento opcional a b: condición. Esto es muy poderoso. Imaginar una situación en la que quería romper sólo si existía una cierta condición. Si pasa una expresión de Python como el segundo argumento, PDB se romperá cuando la expresión se considera verdadero. Haremos esto en un ejemplo a continuación.

En este ejemplo, hay un módulo de utilidad util.py. Vamos a establecer un punto de interrupción de la ejecución de parada en el get_path función ().

Aquí está la fuente de la example4.py script principal:

#!/usr/bin/env python3

import util

filename = __file__
import pdb; pdb.set_trace()
filename_path = util.get_path(filename)
print(f'path = {filename_path}')

Aquí está la fuente de la util.py módulo de utilidad:

def get_path(filename):
"""Return file's path or empty string if no path."""
import os
head, tail = os.path.split(filename)
return head

En primer lugar, vamos a establecer un punto de interrupción utilizando el nombre de archivo y número de línea:

$ ./example4.py
> /code/example4.py(7)()
-> filename_path = util.get_path(filename)
(Pdb) b util:5
Breakpoint 1 at /code/util.py:5
(Pdb) c
> /code/util.py(5)get_path()
-> return head
(Pdb) p filename, head, tail
('./example4.py', '.', 'example4.py')
(Pdb)

El comando c (continuar) continúa la ejecución hasta que se encuentre un punto de interrupción.

A continuación, vamos a establecer un punto de interrupción utilizando el nombre de la función:

$ ./example4.py
> /code/example4.py(7)()
-> filename_path = util.get_path(filename)
(Pdb) b util.get_path
Breakpoint 1 at /code/util.py:1
(Pdb) c
> /code/util.py(3)get_path()
-> import os
(Pdb) p filename
'./example4.py'
(Pdb)

Enter b sin argumentos para ver una lista de todos los puntos de interrupción:

(Pdb) b
Num Type Disp Enb Where
1 breakpoint keep yes at /code/util.py:1
(Pdb)

Usted puede deshabilitar y volver a habilitar los puntos de interrupción utilizando el bpnumber deshabilitar comandos y habilitar bpnumber. bpnumber es el número de punto de interrupción de la lista de puntos de interrupción primera columna Num. Observe el cambio de valor de la columna ENB:

(Pdb) disable 1
Disabled breakpoint 1 at /code/util.py:1
(Pdb) b
Num Type Disp Enb Where
1 breakpoint keep no at /code/util.py:1
(Pdb) enable 1
Enabled breakpoint 1 at /code/util.py:1
(Pdb) b
Num Type Disp Enb Where
1 breakpoint keep yes at /code/util.py:1
(Pdb)

Para eliminar un punto de interrupción, utilice el mandato CL (borrar):

cl(ear) filename:lineno
cl(ear) [bpnumber [bpnumber...]]

Ahora vamos a utilizar una expresión de Python para establecer un punto de interrupción. Imaginar una situación en la que quería romper sólo si su función con problemas recibió una cierta entrada.

En este escenario de ejemplo, la función get_path () está fallando cuando recibe una ruta relativa, es decir, la ruta del archivo no comienza con /. Voy a crear una expresión que se considera verdadero en este caso y pasarla a B como el segundo argumento:

$ ./example4.py
> /code/example4.py(7)()
-> filename_path = util.get_path(filename)
(Pdb) b util.get_path, not filename.startswith('/')
Breakpoint 1 at /code/util.py:1
(Pdb) c
> /code/util.py(3)get_path()
-> import os
(Pdb) a
filename = './example4.py'
(Pdb)

Después de crear el punto de interrupción arriba y escriba c para continuar la ejecución, PDB se detiene cuando la expresión evalúa a verdadero. El comando de un (args) imprime la lista de argumentos de la función actual.

En el ejemplo anterior, cuando se está estableciendo el punto de corte con un nombre de función en lugar de un número de línea, nota que la expresión debe usar sólo argumentos de funciones o variables globales que están disponibles en el momento en que se introdujo la función. De lo contrario, el punto de corte se detendrá la ejecución de la función sin importar el valor de la expresión.

Si usted necesita para romper el uso de una expresión con un nombre de variable ubicada dentro de una función, es decir, un nombre de variable no está en la lista de argumentos de la función, especifique el número de línea:

$ ./example4.py
> /code/example4.py(7)()
-> filename_path = util.get_path(filename)
(Pdb) b util:5, not head.startswith('/')
Breakpoint 1 at /code/util.py:5
(Pdb) c
> /code/util.py(5)get_path()
-> return head
(Pdb) p head
'.'
(Pdb) a
filename = './example4.py'
(Pdb)

También puede establecer un punto de interrupción temporal utilizando el TBREAK comando. Se elimina automáticamente cuando llega el primer golpe. Utiliza los mismos argumentos que b.

Continua ejecución

Hasta ahora, hemos visto recorrer el código con n (al lado) y s (paso) y el uso de puntos de corte con B (rotura) y C (continuar).

También hay un comando relacionado: UNT (hasta).

Uso UNT para continuar la ejecución como C, pero parada en la próxima mayor línea de la línea actual. A veces UNT es más cómodo y rápido de usar y es exactamente lo que quiere. Voy a demostrar esto con un ejemplo a continuación. la primera mirada de

Veamos la sintaxis y la descripción de UNT:

Dependiendo de si o no se pasa la línea de argumento número lineno, unt puede comportarse de dos maneras:

  • Sin lineno, continuar la ejecución hasta que la línea con un número mayor que se alcanza la actual. Esto es similar a n (siguiente). Es una forma alternativa de ejecución y “pasar por encima” de código. La diferencia entre N y unt es que paradas unt sólo cuando se alcanza una línea con un número mayor que el actual. n se detendrá en la siguiente línea lógicamente ejecutado.
  • Con lineno, continuar la ejecución hasta que una línea con un número mayor o igual a la que se alcanza. Esto es como c (continuar) con un argumento de número de línea.

En ambos casos, paradas unt cuando la trama actual (función) devuelve, al igual que n (al lado) y s (paso).

El comportamiento primario de nota con unt es que se detiene cuando se alcanza un número de línea mayor o igual a la línea actual o especificado.

Uso UNT cuando se quiere continuar la ejecución y detener más abajo en el archivo fuente de corriente. Se puede tratar como un híbrido de n (al lado) y B (rotura), dependiendo de si se pasa un argumento número de línea o no.

En el siguiente ejemplo, hay una función con un bucle. A continuación, desea continuar con la ejecución del código y la parada después del bucle, sin pisar a través de cada iteración del bucle o la creación de un punto de ruptura:

Aquí está la fuente de ejemplo para example4unt.py:

#!/usr/bin/env python3

import os

def get_path(fname):
"""Return file's path or empty string if no path."""
import pdb; pdb.set_trace()
head, tail = os.path.split(fname)
for char in tail:
pass # Check filename char
return head

filename = __file__
filename_path = get_path(filename)
print(f'path = {filename_path}')

Y la salida de la consola usando UNT:

$ ./example4unt.py
> /code/example4unt.py(9)get_path()
-> head, tail = os.path.split(fname)
(Pdb) ll
6 def get_path(fname):
7 """Return file's path or empty string if no path."""
8 import pdb; pdb.set_trace()
9 -> head, tail = os.path.split(fname)
10 for char in tail:
11 pass # Check filename char
12 return head
(Pdb) unt
> /code/example4unt.py(10)get_path()
-> for char in tail:
(Pdb)
> /code/example4unt.py(11)get_path()
-> pass # Check filename char
(Pdb)
> /code/example4unt.py(12)get_path()
-> return head
(Pdb) p char, tail
('y', 'example4unt.py')

el comando ll fue utilizado por primera vez para imprimir la fuente de la función, seguido de UNT. AP recuerda el último comando introducido, por lo que acaba de pulsar Intro para repetir el comando UNT. Se llegó a este ejecución continua a través del código hasta que una mayor línea de la fuente de la línea actual.

Nota en la salida de la consola de arriba que pdb detuvo sólo una vez en las líneas 10 y 11. Dado que se utilizó unt, la ejecución se detuvo sólo en la primera iteración del bucle. Sin embargo, fue ejecutado cada iteración del bucle. Esto se puede comprobar en la última línea de salida. El valor de la variable de tipo char ‘y’ es igual al último carácter en el valor de la cola ‘example4unt.py’.

Viendo Expresiones

similar a la impresión expresiones con P y PP, se puede utilizar la pantalla de comandos [expresión] para contar pdb para mostrar automáticamente el valor de una expresión, si ha cambiado, cuando la ejecución se detiene. Utilice el comando undisplay [expresión] para borrar una expresión de visualización.

Ésta es la sintaxis y la descripción de ambos comandos:

continuación se muestra un ejemplo, example4display.py, demostrando su uso con un bucle:

$ ./example4display.py
> /code/example4display.py(9)get_path()
-> head, tail = os.path.split(fname)
(Pdb) ll
6 def get_path(fname):
7 """Return file's path or empty string if no path."""
8 import pdb; pdb.set_trace()
9 -> head, tail = os.path.split(fname)
10 for char in tail:
11 pass # Check filename char
12 return head
(Pdb) b 11
Breakpoint 1 at /code/example4display.py:11
(Pdb) c
> /code/example4display.py(11)get_path()
-> pass # Check filename char
(Pdb) display char
display char: 'e'
(Pdb) c
> /code/example4display.py(11)get_path()
-> pass # Check filename char
display char: 'x' [old: 'e']
(Pdb)
> /code/example4display.py(11)get_path()
-> pass # Check filename char
display char: 'a' [old: 'x']
(Pdb)
> /code/example4display.py(11)get_path()
-> pass # Check filename char
display char: 'm' [old: 'a']

En la salida anterior, pdb muestra automáticamente el valor de la variable de tipo char, porque cada vez que el punto de ruptura fue alcanzado su valor había cambiado. A veces esto es útil y es exactamente lo que quiere, pero no hay otra manera de utilizar la pantalla.

Puede acceder a la pantalla varias veces para construir una lista de vigilancia de expresiones. Esto puede ser más fácil de usar que p. Después de añadir todas las expresiones que estás en interesado, entra pantalla para ver los valores actuales:

$ ./example4display.py
> /code/example4display.py(9)get_path()
-> head, tail = os.path.split(fname)
(Pdb) ll
6 def get_path(fname):
7 """Return file's path or empty string if no path."""
8 import pdb; pdb.set_trace()
9 -> head, tail = os.path.split(fname)
10 for char in tail:
11 pass # Check filename char
12 return head
(Pdb) b 11
Breakpoint 1 at /code/example4display.py:11
(Pdb) c
> /code/example4display.py(11)get_path()
-> pass # Check filename char
(Pdb) display char
display char: 'e'
(Pdb) display fname
display fname: './example4display.py'
(Pdb) display head
display head: '.'
(Pdb) display tail
display tail: 'example4display.py'
(Pdb) c
> /code/example4display.py(11)get_path()
-> pass # Check filename char
display char: 'x' [old: 'e']
(Pdb) display
Currently displaying:
char: 'x'
fname: './example4display.py'
head: '.'
tail: 'example4display.py'

Python Caller ID

En este último apartado, vamos a construir sobre lo que hemos aprendido hasta ahora y con un acabado buena recompensa. Yo uso el nombre de “identificador de llamadas”, en referencia a la función de identificación de llamadas del sistema telefónico. Eso es exactamente lo que demuestra este ejemplo, excepto que se aplica a Python.

Aquí está la fuente de la example5.py script principal:

#!/usr/bin/env python3

import fileutil

def get_file_info(full_fname):
file_path = fileutil.get_path(full_fname)
return file_path

filename = __file__
filename_path = get_file_info(filename)
print(f'path = {filename_path}')

Aquí está la fileutil.py módulo de utilidad:

def get_path(fname):
"""Return file's path or empty string if no path."""
import os
import pdb; pdb.set_trace()
head, tail = os.path.split(fname)
return head

En este escenario, imagina que hay una gran base de código con una función en un módulo de servicios públicos, get_path (), que de se llama con la entrada no válida. Sin embargo, está siendo llamado desde muchos lugares en diferentes paquetes.

¿Cómo se encuentra que la persona que llama es?

Utilice el comando w (dónde) para imprimir un seguimiento de la pila, con el marco más reciente en la parte inferior:

$ ./example5.py
> /code/fileutil.py(5)get_path()
-> head, tail = os.path.split(fname)
(Pdb) w
/code/example5.py(12)()
-> filename_path = get_file_info(filename)
/code/example5.py(7)get_file_info()
-> file_path = fileutil.get_path(full_fname)
> /code/fileutil.py(5)get_path()
-> head, tail = os.path.split(fname)
(Pdb)

No se preocupe si esto parece confuso o si no está seguro de lo que es un seguimiento de pila o el marco . Voy a explicar esos términos a continuación. No es tan difícil como puede parecer.

Desde el marco más reciente es en la parte inferior, se inicia allí y leer desde la parte inferior hacia arriba. Vistazo a las líneas que comienzan con ->, pero no tome la primera instancia ya que es donde se utilizó pdb.set_trace () para entrar en el PDB get_path función (). En este ejemplo, la línea de origen que llama la get_path función () es:

-> file_path = fileutil.get_path(full_fname)

La línea de arriba de cada -> contiene el nombre del archivo, número de línea (entre paréntesis), y el nombre de la función de la línea de fuente está en modo que la persona que llama.:

/code/example5.py(7)get_file_info()
-> file_path = fileutil.get_path(full_fname)

Eso no es una sorpresa en este pequeño ejemplo para fines de demostración, pero imagina una gran aplicación en la que ha establecido un punto de interrupción con una condición para identificar donde un valor de entrada es mala de origen.

Ahora sabemos cómo encontrar la persona que llama.

Pero ¿qué pasa con este seguimiento de la pila y la materia marco?

Una pila traza es sólo una lista de todos los marcos que Python ha creado para realizar un seguimiento de las llamadas a funciones. Un marco es una estructura de datos de Python crea cuando una función es llamada y eliminaciones cuando se devuelve. La pila es simplemente una lista ordenada de tramas o llamadas a funciones en cualquier punto en el tiempo. El (llamada de función) pila crece y se contrae a lo largo de la vida de una aplicación como funciones son llamados y luego regresar.

Cuando impresa, esta lista ordenada de tramas, la pila, se llama un seguimiento de pila. Se puede ver en cualquier momento introduciendo el comando w, tal como lo hicimos anteriormente para encontrar la persona que llama.

Véase el artículo esta llamada pila en la Wikipedia para más detalles.

Para entender mejor y sacar más provecho de la AP, veamos más de cerca la ayuda de w:

(Pdb) h w
w(here)
Print a stack trace, with the most recent frame at the bottom.
An arrow indicates the "current frame", which determines the
context of most commands. 'bt' is an alias for this command.

¿Qué significa AP en “cuadro actual”?

Piense en el cuadro actual como la función actual en la que se ha detenido la ejecución AP. En otras palabras, el cuadro actual es donde la aplicación está en pausa y se utiliza como el “marco” de referencia para los comandos pdb como p (impresión).

p y otros comandos utilizarán el cuadro actual de contexto cuando sea necesario. En el caso de p, el marco actual se utilizará para buscar e imprimir referencias a variables.

Cuando pdb imprime un seguimiento de la pila, una flecha indica > el cuadro actual.

¿Cómo es esto útil?

Puede utilizar los dos comandos u (arriba) y D (abajo) para cambiar el marco actual. En combinación con p, esto le permite inspeccionar variables y el estado de su solicitud en cualquier punto a lo largo de la pila de llamadas en cualquier marco.

Ésta es la sintaxis y la descripción de los dos comandos: la mirada de

Veamos un ejemplo utilizando los comandos U y D. En este escenario, queremos inspeccionar el full_fname variable que es local a la get_file_info () en example5.py. Con el fin de hacer esto, tenemos que cambiar el marco actual a un nivel superior con el comando u:

$ ./example5.py
> /code/fileutil.py(5)get_path()
-> head, tail = os.path.split(fname)
(Pdb) w
/code/example5.py(12)()
-> filename_path = get_file_info(filename)
/code/example5.py(7)get_file_info()
-> file_path = fileutil.get_path(full_fname)
> /code/fileutil.py(5)get_path()
-> head, tail = os.path.split(fname)
(Pdb) u
> /code/example5.py(7)get_file_info()
-> file_path = fileutil.get_path(full_fname)
(Pdb) p full_fname
'./example5.py'
(Pdb) d
> /code/fileutil.py(5)get_path()
-> head, tail = os.path.split(fname)
(Pdb) p fname
'./example5.py'
(Pdb)

La llamada a pdb.set_trace () está en fileutil.py en el get_path función (), por lo que el cuadro actual es inicialmente puesto en ella. Se puede ver en la primera línea de salida por encima de: el acceso

> /code/fileutil.py(5)get_path()

Para e imprimir la variable local en el full_fname get_file_info () en example5.py, el comando T se utilizó para subir un nivel:

(Pdb) u
> /code/example5.py(7)get_file_info()
-> file_path = fileutil.get_path(full_fname)

Nota de la salida de u por encima de ese AP impresa la flecha > al principio de la primera línea. Esta es pdb que le permite saber la trama fue cambiado y esta ubicación de origen ahora es el cuadro actual. El full_fname variable es accesible ahora. Además, es importante darse cuenta de la línea de origen a partir de -> en la segunda línea ha sido ejecutada. Puesto que el bastidor se mueve hacia arriba la pila, fileutil.get_path () ha sido llamado. El uso de u, nos cambiamos la pila (en un sentido, en el tiempo) a la example5.get_file_info función (), donde fileutil.get_path () se llama.

Continuando con el ejemplo, después de que se imprime full_fname, la trama actual se trasladó a su ubicación original usando d, y la fname variable local en get_path () se ha impreso.

Si quisiéramos, podríamos haber movido varias imágenes a la vez pasando el argumento de recuento a u o d. Por ejemplo, podríamos haber movido a nivel de módulo en example5.py mediante la introducción de u2:

$ ./example5.py
> /code/fileutil.py(5)get_path()
-> head, tail = os.path.split(fname)
(Pdb) u 2
> /code/example5.py(12)()
-> filename_path = get_file_info(filename)
(Pdb) p filename
'./example5.py'
(Pdb)

Es fácil olvidar dónde estás cuando estás depuración y el pensamiento de muchas cosas diferentes. Sólo recuerda que siempre puedes utilizar el comando bien llamado w (dónde) para ver si la ejecución se detiene y lo que el cuadro actual es.

AP esencial Comandos

Una vez que haya pasado un poco de tiempo con AP, se dará cuenta un poco de conocimiento va un largo camino. La ayuda está siempre disponible con el comando h.

introduce ho ayuda para obtener una lista de todos los comandos y ayuda para un comando específico o tema.

Para tener una referencia rápida, he aquí una lista de los comandos esenciales: Depuración de Python

Con pdb: Conclusión

En este tutorial, hemos cubierto algunos usos básicos y comunes de AP:

  • impresión expresiones
  • recorrer el código con n (siguiente) y s (paso)
  • con puntos de parada
  • ejecución con expresiones UNT (hasta)
  • que muestran
  • la búsqueda de la persona que llama de una función

espero que ha sido útil para usted continua. Si tienes curiosidad por aprender más, vea: documentación completa de

  • AP en una pdb pronta cerca de usted: (PDB) h pdb de
  • Python documentos PDB

El código fuente utilizado en los ejemplos se puede encontrar en la asociada repositorio GitHub. Asegúrese de revisar nuestra pdb imprimible Referencia de comandos, que se puede utilizar como una hoja de trucos durante la depuración: Bonus

gratuito: Haga clic aquí para obtener una impresión «pdb mandatos» (PDF) que se puede mantener en su escritorio y se refieren a durante la depuración.

Además, si desea probar un depurador de Python basado en GUI, lea nuestra Guía IDE Python y Editores para ver qué opciones funcionarán mejor para usted. Feliz Pythoning!

Mira ahora Este tutorial tiene un vídeo relacionado curso creado por el equipo del Real Python. Mira que junto con el tutorial escrito para profundizar su comprensión: Python Depuración con pdb

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *