Vés al contingut

Python 3 per a no programadors/Depuració

Què és depurar (debugging)?

[modifica]
"Tan aviat com comencem a programar, ens trobem amb la sorpresa que no tenir programes correctes no és tan fàcil com havíem pensat. S'havia de descobrir la depuració. Puc recordar l'instant exacte en què me'n vaig adonar que una gran part de la meva vida des de llavors ençà es dedicaria a trobar equivocacions en els meus propis programes." - Maurice Wilkes descobreix la depuració, 1949

A hores d'ara si heu estat trastejant amb els programes probablement haureu trobat que a vegades el programa fa alguna cosa que no volíeu que fes. Això és bastant habitual. La depuració és el procés d'imaginar què està fent l'ordinador i llavors aconseguir que faci el que voleu que faci. Això pot ser delicat. Una vegada vaig dedicar gairebé una setmana ressegint i corregint un error que era provocat per algú que pitjava x on hauria d'haver pitjat y.

Aquest capítol serà més abstracte que els capítols previs.

Què hauria de fer el programa?

[modifica]

La primera cosa a fer (això sona obvi) és imaginar què hauria d'estar fent el programa si s'està executant correctament. Definiu alguns casos de prova i vegeu què passa. Per exemple, diguem que tinc un programa per calcular el perímetre d'un rectangle (la suma de la llargada de tots els costats). Tinc els següents casos de prova:

alçada amplada perímetre
3 4 14
2 3 10
4 4 16
2 2 8
5 1 12

Ara executo el meu programa en tots els casos de prova i veig si el programa fa el que espero que faci. Si no ho fa llavors necessito esbrinar què està fent l'ordinador.

El més habitual és que alguns dels casos de prova funcionin i altres no. Si aquest és el cas hauria de provar d'entendre què tenen en comú els que funcionen. Per exemple, aquí hi ha el resultat d'un programa de càlcul del perímetre (veureu el codi en un minut):

Alçada: 3
Amplada: 4
perímetre = 15
Alçada: 2
Amplada: 3
perímetre = 11
Alçada: 4
Amplada: 4
perímetre = 16
Alçada: 2
Amplada: 2
perímetre = 8
Alçada: 5
Amplada: 1
perímetre = 8

Fixeu-vos que no funcionava pels dos primers casos, funcionava pels dos següents i no funcionava a l'últim. Proveu d'entendre què tenen en comú els casos que funcionen. Una vegada teniu alguna idea de quin és el problema és més fàcil trobar la causa. Amb els vostres propis programes hauríeu de provar més casos si cal.

Què fa el programa?

[modifica]

La pròxima cosa a fer és mirar el codi font. Una de les coses més importants a fer al programar és llegir el codi font. La manera immediata de fer-ho és passejar-se pel codi.

Una passejada pel codi comença en la primera línia, i segueix el seu camí fins que el programa s'acaba. Els bucles while i les instruccions if volen dir que algunes línies poden no executar-se mai i altres poden executar-se moltes vegades. En cada línia imagina què ha fet Python.

Comencem amb el programa de càlcul del perímetre. No el teclegeu, el llegireu, no l'executareu. El codi font és:

alçada = int(input("Alçada: "))
amplada = int(input("Amplada: "))
print("perímetre =", amplada + alçada + amplada + amplada)
Pregunta: Quina és la primera línia de Python que s'executa?
Resposta: La primera línia sempre s'executa primer. En aquest cas és: alçada = int(input("Alçada: "))
Què fa aquesta línia?
Escriu Alçada: , espera que l'usuari hi teclegi una cadena, i llavors transforma la cadena en una variable entera anomenada "alçada".
Quina és la següent línia que s'executa?
En general, és la següent línia que és: amplada = int(input("Amplada: "))
Què fa aquesta línia?
Escriu Amplada: , espera que l'usuari hi teclegi un nombre, i fica el que l'usuari teclegi a la variable "amplada".
Quina és la següent línia que s'executa?
Quan la següent línia no està sagnada més o menys que la actual, és la línia immediata següent en executar-se, per tant és: print("perímetre =", amplada + alçada + amplada + amplada) (També es pot executar una funció en la línia actual però això s'explicarà en un capítol posterior.)
Què fa aquesta línia?
Primer escriu perímetre = , llavors escriu amplada + alçada + amplada + amplada.
amplada + alçada + amplada + amplada calcula el perímetre adequadament?
Vegem, el perímetre d'un rectangle és la base (amplada) més el costat esquerre (alçada) més la part superior (amplada) més el costat dret (Oh!). L'últim element hauria de ser la llargada del costat dret, és a dir l'alçada.
Enteneu perquè de vegades el perímetre es calculava "correctament"?
Es calculava correctament quan l'amplada i l'alçada eren iguals.

El pròxim programa per al qual farem una passejada pel codi és un programa del qual se suposa que escriu 5 punts a la pantalla. Tanmateix, això és el què està escrivint el programa:

. . . . 

I aquest és el programa:

nombre = 5
while nombre > 1:
    print(".",end=" ")
    nombre = nombre - 1
print()

Per aquest programa serà més complex de passejar-se-hi perquè té bocins sagnats (o estructures de control). Comencem.

Quina és la primera línia a executar?
La primera línia del programa: nombre = 5
Què fa?
Posa el nombre 5 a la variable "nombre".
Quina és la següent línia?
La següent línia és: while nombre > 1:
Què fa?
Be, les instruccions while en generarl miren l'expressió que tenen a continuació, i si és certa executen el següent bloc de codi sagnat, altrament se'l salten.
Llavors que fa en aquest cas?
Si nombre > 1 és cert llavors s'executen les següents dues línies.
I nombre > 1 és cert?
L'últim valor ficat a number era 5 i 5 > 1 per tant sí que ho és.
Per tant quina és la següent línia?
Com que el while era cert la següent línia és: print(".",end=" ")
Què fa aquesta línia?
Escriu un punt i com que l'argument extra end=" " existeix la següent línia que s'escrigui no encetarà una nova línia a la pantalla.
Quna és la línia següent?
nombre = nombre - 1 ja que és la línia següent i no hi ha canvis de sagnat.
Què fa?
Calcula nombre - 1, que és el valor actual de nombre (o 5) li resta 1, i el fa el nou valor de "nombre". Per tant bàsicament canvia el valor de nombre de 5 a 4.
Quina és la següent línia?
Be, el nivell de sagnat disminueix per tant cal mirar quin tipus de estructura de control és. És un bucle while, així cal tornar enrere cap a la clàusula while que és while nombre > 1:
Què fa?
Mira el valor de "nombre", que és 4, i el compara amb 1 i com que 4 > 1 continua el bucle while.
Quina és la següent línia?
Com que el bucle while ha estat cert, la següent línia és: print(".",end=" ")
Què fa?
Escriu un segon punt a la línia, acabat amb un espai.
Quina és la següent línia?
No hi ha canvi de sagnat per tant és: nombre = nombre - 1
I què fa?
Agafa el valor actual de "nombre" (4), li resta 1, que dóna 3 i finalment fa que sigui 3 el nou valor de "nombre".
Quina és la següent línia?
Com que hi ha un canvi de sagnat causat pel final del bucle while, la següent línia és: while nombre > 1:
Què fa?
Compara el valor actual de "nombre" (3) amb 1. 3 > 1 per tant continua el bucle while.
Quina és la següent línia?
Com que el bucle while ha estat cert, la següent línia és: print(".",end=" ")
I fa què?
S'escriu un tercer punt a la línia.
Quina és la següent línia?
És: nombre = nombre - 1
Què fa?
Agafa el valor actual de "nombre" (3) li resta 1 i fa que el 2 sigui el nou valor de "nombre".
Quina és la següent línia?
Tornem al començament del bucle while: while nombre > 1:
Què fa?
Compara el valor actual de "nombre" (2) amb 1. com que 2 > 1 continua el bucle while.
Quina és la següent línia?
Com que el bucle while continua: print(".",end=" ")
Què fa?
Descobreix el significat de la vida, l'univers i de tot. És broma, m'havia d'assegurar que estàveu desperts. La línia escriu un quart punt a la pantalla.
Quina és la següent línia?
És: nombre = nombre - 1
Què fa?
Agafa el valor actual de "nombre" (2) li resta 1 i fa que el 1 sigui el nou valor de "nombre".
Quina és la següent línia?
Tornem al començament del bucle while: while nombre > 1:
Què fa aquesta línia?
Compara el valor actual de "nombre" (1) amb 1. com que 1 > 1 és fals (u no és més gran que u), surt del bucle while.
Quina és la següent línia?
Com que la condició del bucle while era falsa la següent línia és la línia de després de sortir del bucle while, o sigui: print()
Què fa aquesta línia?
Fa que la pantalla vagi a la següent línia.
Perquè el programa no escriu 5 punts?
El bucle s'acaba un punt massa aviat.
Com ho podem arreglar?
Fent que el loop s'acabi un punt més tard.
I com ho fem?
Hi ha diverses formes. Una forma seria canviar el bucle while a: while nombre > 0: Un altre forma seria canviar el condicional a: number >= 1 N'hi ha d'altres.

Com arreglo el meu programa?

[modifica]

Necessiteu entendre què està fent el programa. Necessiteu imaginar què hauria de fer el programa. Imagineu quina és la diferència entre els dos. La depuració és una habilitat que s'ha de practicar per aprendre-la. Si no ho podeu entendre passada una hora, feu una pausa, parleu amb algú sobre el problema o rasqueu-vos el melic. Torneu al cap d'una estona i probablement tindreu idees noves sobre el problema. Bona sort.