0% encontró este documento útil (0 votos)
92 vistas

Python Reparando Bugs

Este documento describe cómo depurar programas Python utilizando el depurador integrado de Python (PDB). PDB permite al programador insertar puntos de interrupción y examinar el estado del programa y las variables mientras se ejecuta. El documento también discute los tipos comunes de errores (bugs) que ocurren en Python, como errores sintácticos y semánticos. Finalmente, el documento proporciona un ejemplo de código con un error y muestra cómo PDB puede usarse para identificar y corregir el error.

Cargado por

miteratos
Derechos de autor
© Attribution Non-Commercial (BY-NC)
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
92 vistas

Python Reparando Bugs

Este documento describe cómo depurar programas Python utilizando el depurador integrado de Python (PDB). PDB permite al programador insertar puntos de interrupción y examinar el estado del programa y las variables mientras se ejecuta. El documento también discute los tipos comunes de errores (bugs) que ocurren en Python, como errores sintácticos y semánticos. Finalmente, el documento proporciona un ejemplo de código con un error y muestra cómo PDB puede usarse para identificar y corregir el error.

Cargado por

miteratos
Derechos de autor
© Attribution Non-Commercial (BY-NC)
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
Está en la página 1/ 4

DESARROLLO Python: Debuggers

Eliminacin de bugs de programas Python

DESPARASITANDO SERPIENTES
Da igual lo buenos programadores que seamos, tarde o temprano daremos con ese BUG que ser nuestro peor enemigo. Veamos cmo podemos emplear herramientas para derrotarlo con mayor facilidad. POR JOSE MARA RUZ

quivocarse es humano y, a pesar de todo el mito que rodea a los programadores, hasta el mejor de ellos comete errores diariamente. En muchas ocasiones es mucho ms complicado eliminar un BUG que crear el propio programa. Cuenta le leyenda que el nombre de BUG viene de la misma palabra que en ingls significa bicho. Dicen que los primeros ordenadores eran grandes mquinas que generaban gran cantidad de calor, por lo que innumerables insectos y otras alimaas se introducan en ellos. De vez en cuando alguno tocaba dos cables y quedaba frito, provocando un fallo en el sistema. Actualmente se conoce como BUG a todo error o situacin no controlada que impida a un programa realizar su tarea con normalidad. Lo cierto es que estamos bastante acostumbrados a que los BUGS sean parte de nuestra vida. Ventanas que no se cierran, programas que consumen todo el espacio en memoria o videojuegos que se quedan bloqueados. Python es un lenguaje dinmico, como muchos otros. La principal ventaja es que nos permite programar a alto nivel, desentendindonos de toda la gestin de recursos a

bajo nivel que hace tan pesada la programacin en otros lenguajes como por ejemplo C. Pero no todo el monte es organo. Tambin hay una parte negativa: Python no es un lenguaje demasiado estricto. Podemos hacer lo que queramos con las variables sin que el intrprete se queje hasta el ltimo momento. Esta caracterstica impide la posibilidad de verificar automticamente todo el cdigo en el momento en que es compilado. Un cdigo totalmente errneo, en el que por ejemplo se suman letras y nmeros, puede pasar desapercibido en nuestro programa hasta el da que se ejecuta y genera un error que dejar al usuario con la boca abierta y ciertas dudas sobre nuestra vala como programadores. Casi a la vez que surgieron los lenguajes de programacin aparecieron unos programas que van unidos a ellos: los debuggers. Existen muchos debuggers diferentes. GNU desarroll DDD, pero hace tiempo que no se ve actividad en este proyecto (ver Recurso [1]). Valgrind ha conseguido mucha fama en proyectos que emplean C++ ( ver Recurso [2]). En este artculo vamos a echar un vistazo a las herramientas que podemos usar para

localizar los fallos en nuestros programas Python y en particular a la que viene de serie con Python: el PDB, Python DeBugger (podemos ver la documentacin de PDB en el Recurso [3]).

Un Bug, Dos Bugs, Tres Bugs


Los lenguajes dinmicos, como decamos antes, tienen sus propias virtudes y desventajas. Los programadores ms duros suelen decir que programar con lenguajes dinmicos es como jugar con juguetes: no hay bordes afilados con los que cortarse ni partes pequeas con las que atragantarnos. Vamos, que son poco menos que una versin infantil de los lenguajes serios. Lo cierto es que hay mucha gente que no entra en estos debates. Yo, por lo menos, prefiero hacer un programa tan rpido como sea posible y espero que funcione casi a la primera. De dnde salen los BUGS? Lo ms probable es que haya siempre una variable implicada. La explicacin es simple: las variables son la nica parte del programa que realmente no controlamos. Mientras el resto del cdigo hace exactamente lo que le indica-

50

Nmero 34

WWW.LINUX- MAGAZINE.ES

Python: Debuggers DESARROLLO

mos que haga, por ejemplo abrir un fichero, en las variables suceden todo tipo de cosas mientras el programa est en ejecucin. El problema es que no vemos esas variables mientras el programa est funcionando, as que tenemos que imaginarnos qu est pasando. En condiciones ideales se puede perder el tiempo tratando de localizar los fallos a ojo de buen cubero, pero bajo estrs y con plazos, toda ayuda es poca. Python adems nos permite almacenar cualquier valor dentro de una variable. Las variables en los lenguajes dinmicos como Python son casi mgicas. En ellas podemos almacenar un nmero:
>>> mivariable = 32

TypeError: unsupported operand type(s) for +: instance and int >>>

Y punto seguido almacenar un objeto:


>>> class Persona: ... def __init__(this,nombre): ... this.nombre = nombre ... >>> mivariable = PersonaU (Carlos)

Y sigue siendo la misma mivariable, pero de alguna manera su naturaleza ha cambiado. Ahora imagina que esta situacin ocurre en un programa que has creado. Mientras tecleas piensas, mivariable contiene una distancia y operas con ella, slo que, sin que te des cuenta, en realidad mivariable contiene un objeto de la clase Persona qu pasara si intentas sumarle 18?
>>> a + 18 Traceback (most recent call last): File <stdin>, line 1, in ?

ERROR! El intrprete de Python nos advierte de que algo no marcha bien: hay un error de tipo, no es posible sumar un nmero entero y una instancia de un objeto tal como hemos definido la clase. Desagradable verdad? Por lo menos este tipo de BUG, que es tan fcil de encontrar que el propio intrprete de Python lo encuentra. Qu ocurra si el programa no fallase, sino que no nos diese el resultado esperado? Y si el programa le dijese a un cliente que su edad actual es -323134.32 aos? Este es sin duda el peor tipo de BUG existente: el semntico. El intrprete de Python es perfecto localizando errores sintcticos, aqullos que tienen que ver con las propias palabas que escribimos. Si hacemos referencia a una variable que no est definida, Python trata de buscar su valor, ve que no existe la variable y se queja. Los errores semnticos son harina de otro costal, porque se refieren a fallos que aparecen debido a que no se entiende lo que est pasando. Un ejemplo simple es el que hemos visto antes, cuando hemos tratado de sumar una variable con una instancia de un objeto que no responde a la suma con un nmero. Solucionar un BUG semntico puede llevar desde segundos a aos. De hecho, existe mucho software, tanto comercial como libre, con BUGS que no han sido resueltos en aos (como por ejemplo el fallo de Excel, que ya vimos en el artculo dedicado a Gnumeric). Ahora que el problema ha sido planteado con ms detenimiento con-

Figura 1: A quin dejaremos sin vacaciones?

viene ver con qu arsenal contamos en nuestra batalla contra los BUGS.

Depurando Cdigo
Digamos que estamos haciendo un script para mostrar usando caracteres las vacaciones que han escogido una serie de empleados de una empresa. Como no queremos que el cdigo sea largo ni demasiado complicado, lo hemos reducido al mnimo. La funcin tomar una lista de tuplas, que representa las vacaciones de una persona en un mes. Cada tupla representa un periodo de vacaciones, con una fecha de inicio y una fecha de fin. La idea es muy simple, aceptamos esa lista y despus devolvemos una cadena donde los das de trabajo se representan por un espacio, y los de vacaciones con un #. No muy complicado verdad? As que nos ponemos manos a la obra.Es algo sencillo, y no nos llevar ni 10 minutos, acabamos escribiendo el cdigo del Listado [1]. Pero nos interrumpen antes de probar la funcin, y cuando volvemos al ordenador y ejecutamos un programa de prueba se queda bloqueado! No puede ser!. En tan pocas lneas de cdigo no puede haber un error tan grave. Despus de unos minutos de frustracin abandonamos la inspeccin visual y pasamos a trabajar PDB. PDB es el Python DeBugger y viene de serie con Python. Eso est muy bien, porque en caso de necesitarlo, siempre lo tendremos a mano. A diferencia de otros debuggers PDB se puede usar como si fuese una librera. Podemos integrarla en nuestros programas y eliminarla cuando ya los hayamos arreglado. Como es posible observar en el Listado 1, hemos importado PDB y hemos pasado como parmetro a pdb.run() una cadena en la que invocamos la funcin vacaciones() con un argumento acorde. Si ejecutamos el programa veremos lo siguiente en nuestro terminal:
josemaria@linuxmagazine$U ./p.py > <string>(1)?() (Pdb)

Listado 1: El cdigo nefasto


01 #!/usr/local/bin/python 02 03 import pdb 04 05 def vacaciones (l): 06 cadena = 07 for i in range(1,31): 08 encontrado = False 09 max = len(l) 10 k=0 11 while(not(encontrado) or k<max): 12 rango = l[k] 13 inf,sup=rango 14 if ((i >= inf) and (i <= 15 16 17 18 19 20 21 22 23 24 25 26 sup)): encontrado = True else: k+=1 if (encontrado): cadena += # else: cadena += return cadena

pdb.run(vacaciones([(1,3),(6, 10)]))

WWW.LINUX- MAGAZINE.ES

Nmero 34

51

DESARROLLO Python: Debuggers

Podemos ver lo que hace un comando usando de nuevo la letra h:


(Pdb) h l l(ist) [first [,last]] List source code for the current file. Without arguments, list 11 lines around the current line or continue the previous listing. With one argument, list 11 lines starting at that line. With two arguments, list the given range; if the second argument is less than the first, it is a count. (Pdb)

Figura 3: El depurador de IDLE.

Figura 2: IDLE no es bello, pero es prctico.

Muy bien, el PDB comienza a hacer su trabajo. En lugar de no hacer nada, como hara la funcin vacaciones() si el programa se limitase a ejecutarla, entramos en lo que parece el prompt del shell de PDB. Esta shell tiene sus propios comandos, que no tienen nada que ver con los Python. Para ver los comandos disponibles podemos emplear el comando h:
(Pdb) h Documented commands (type help <topic>): ================================= EOF break condition disable help list q step w a bt cont down ignore n quit tbreak whatis alias c continue enable j next r u where args cl d exit jump p return unalias b clear debug h l pp s up Miscellaneous help topics: ========================== exec pdb Undocumented commands: ====================== retval rv (Pdb)

El comando l sirve para mostrar visualmente en qu parte del cdigo estamos en un momento dado. Como nos pica la curiosidad ejecutamos l:
(Pdb) l [EOF]

-> cadena = (Pdb) s > /home/josemaria/p.py(7) vacaciones() -> for i in range(1,31): (Pdb) s > /home/josemaria/p.py(8) vacaciones() -> encontrado = False (Pdb) s > /home/josemaria/p.py(9) vacaciones() -> max = len(l) (Pdb)

Vaya. Resulta que no hemos comenzado an, por lo que no estamos en ninguna parte. El comando que probablemente usemos ms a menudo es s Por qu? pues porque es el comando que hace que PDB avance una lnea y la ejecute:
(Pdb) s Call > /home/josemaria/p.py(5)U vacaciones() -> def vacaciones (l):

Hemos avanzado 4 pasos y puede que nos hayamos perdido. Dnde estamos? Qu estamos haciendo? Hacia dnde vamos? El comando l resuelve todas nuestras dudas:
(Pdb) l 4 5 def vacaciones (l): 6 cadena = 7 for i in range(1,31): 8 encontrado = False 9 -> max = len(l) 10 k=0 11 while(not(encontrado) or k<max): 12 rango = l[k] 13 inf,sup=rango 14 if ((i >= inf) and (i <= sup)): (Pdb)

Muy bien, comenzamos a ejecutar el trozo de cdigo Python que pasamos a pdb.run(). Por el momento no pasa nada interesante, aunque estara bien ver qu contiene la variable l, para ello podemos usar el comando p que hace las funciones de print:
(Pdb) p l [(1, 3), (6, 10)]

Buff! estos son demasiados comandos. Como suele ocurrir la primera vez que un principiante en Linux pulsa dos veces tabulador en BASH, lo que vemos nos asusta. En este caso no son tantos comandos (en un Linux estndar hay miles de ejecutables), pero s ms extraos. Debuggear es algo que SIEMPRE se hace bajo presin, por lo que todo el tiempo que ahorremos es de oro. As que los creadores de PDB nos ahorran segundos reduciendo los comandos a letras.

Ya me sito: acabamos de entrar en el bucle for, avancemos un poco ms:


(Pdb) s > /home/josemaria/p.py(10)U vacaciones() -> k=0 (Pdb) s > /home/josemaria/p.py(11)U vacaciones() -> while(not(encontrado) orU k<max): (Pdb)

Efectivamente, l contiene el parmetro que hemos pasado a la funcin. Ya estamos en marcha, as que avancemos unos cuantos pasos ms:
(Pdb) s > /home/josemaria/p.py(6) vacaciones()

52

Nmero 34

WWW.LINUX- MAGAZINE.ES

Python: Debuggers DESARROLLO

Bueno, llegamos a una encrucijada. Cuando ejecutamos la funcin sin PDB parece como si el programa nunca acabase. Esto implica que hay algo que se repite eternamente. En este programa hay dos bucles, que son los nicos elementos que pueden repetirse eternamente. El primero es un bucle for con un principio, 1, y un fin, 31, por lo que podemos descartarlo como culpable. El segundo sospechoso es ese bucle while, que en un primer momento no tiene porqu acabar, puede que jams pare. Si un bucle while no para es porque las condiciones que lo controlan siempre se dan. En este cdigo se supone que el if dentro del bucle while hace que ste pare alguna vez, as que algo debe fallar ah dentro. Comencemos comprobando los valores de las variables que controlan el bucle:
(Pdb) p encontrado False (Pdb) p k 0 (Pdb) p max 2 (Pdb)

variable encontrado sea True. Si todo va bien el, siguiente paso despus de evaluar las condiciones del while ser salir del mismo y pasar a las siguiente instruccin fuera del while:
(Pdb) s > /home/josemaria/p.py(12)U vacaciones() -> rango = l[k] (Pdb)

Pero qu pasa aqu? Esto no debera pasar. La nica explicacin posible es que la condicin del while est es eso un or? Debera ser un and! Deberamos salir si hemos encontrado que el da pertenece a un rango, o si no quedan rangos que comprobar. Ah estaba nuestro BUG, tres simples letras, se cambian y problema solucionado. Ahora que ya sabemos lo que pasa, slo queda salir del debugger usando el comando q. Nuestro nuevo cdigo ya est listo para ser usado (ver Figura 1).

Figura 4: El seudo-editor de IDLE.

Y Ahora de Forma Fcil


No hay una manera ms moderna de conseguir esto mismo? Pues s, gracias a IDLE (ver Recurso [4]). IDLE es el entorno de desarrollo que viene, tambin, junto a Python. En la Figura 2 se puede observar el aspecto que tiene IDLE una vez que se ejecuta. No es ninguna belleza pero es prctico, reemplaza al intrprete de comandos de Python y simplifica algunas tareas. En particular estamos interesados en cmo puede simplificar el debugging. Para ello slo tenemos que ir al men Debug que aparece en la barra de men de IDLE y activar Debugger. Aparecer una ventana como la que puede observarse en la Figura 3. El lector no debe extraarse demasiado con esta nueva ventana, viene a condensar en un solo lugar todo lo que hemos visto sobre PDB: hay un botn llamado STEP, que nos permitir avanzar en el cdigo paso a paso, tambin hay un rea llamada Locals, donde iremos viendo el valor de las variables que se vayan declarando en el cdigo, de forma que podremos ir controlando la evolucin del programa de un solo vistazo. Para ello slo tenemos que cargar el programa en IDLE y veremos cmo se abre una especie de editor de textos como el de la Figura 4, en el que debe-

remos seleccionar en el men Run la opcin Run Module. Con este paso cargaremos el fichero y comenzaremos a ejecutarlo. Como antes seleccionamos la opcin Debugger, IDLE se cargar en la ventana de debugging y podremos comenzar a ver la evolucin del programa conforme pulsemos sobre el botn Step. No es que IDLE sea un gran avance respecto al uso de PDB, pero desde luego simplifica el debugging.

Conclusin
Los debuggers no son una excusa para crear programas sin fijarnos demasiado en los problemas. Pero si no tenemos claro qu est ocurriendo o si ya no sabemos qu hacer, entonces un debugger como PDB puede ayudarnos a tener una imagen ms clara de lo que pasa en nuestro programa. Existen bugs que no pueden cazarse con PDB, pero son tan extraordinariamente raros, que es posible que jams nos encontremos con uno. Los debuggers nos permiten programar sin miedo a no entender lo que estamos haciendo, y es precisamente eso lo que nos permitir avanzar y aprender ms rpidamente. PerdI mosle el miedo a los BUGS!

De acuerdo, todo parece en su sitio. Si avanzamos un poco:


> /home/josemaria/p.py(12) vacaciones() -> rango = l[k] (Pdb) s > /home/josemaria/p.py(13) vacaciones() -> inf,sup=rango (Pdb) s > /home/josemaria/p.py(14) vacaciones() -> if ((i >= inf) and (i <= sup)): (Pdb) s > /home/josemaria/p.py(15) vacaciones() -> encontrado = True (Pdb) s > /home/josemaria/p.py(11) vacaciones() -> while(not(encontrado) or k<max): (Pdb)

RECURSOS
[1] Documentacin del depurador PDB: http://docs.python.org/lib/ module-pdb.html [2] Valgrind captura errores que comprometen la memoria en: http://valgrind. org/ [3] Data Display Debugger: http://www. gnu.org/software/ddd/ [4] El entorno de desarrollo IDLE: http:// www.python.org/idle/

Resulta que hemos entrado en una tupla que representa unas vacaciones, el da representado por i pertenece a las vacaciones. Por tanto, hemos hecho que la

WWW.LINUX- MAGAZINE.ES

Nmero 34

53

También podría gustarte