Skip to content

Errors i excepcions

1. Tipus d'errors

Podem cometre errors mentre programem. Estos errors es poden classificar bàsicament en dos tipus:

  1. Errors de sintaxi
  2. Errors en la lògica (Excepcions)

Els erros de sintaxi es produixen abans de l'execució, mentre que els erros lògics es produixen en temps d'execució.

2. Excepcions

Algun exemple d'excepció són els següents:

  • Quan intentem obrir un fitxer (per llegir) que no existeix (FileNotFoundError)
  • Quan intentem dividir un nombre per zero (ZeroDivisionError)
  • Quan intentem importar un mòdul que no existeix (ImportError).

Sempre que es produeixen aquests tipus d’errors d’execució, Python crea un objecte d’excepció. Si no el tractem, interrumpeix l'execució i imprimeix una traça de l'error juntament amb alguns detalls sobre per què ha produït aquest error.

2.1. Excepcions definides en Python

Per a consultar totes les excepcions definides podem utilitzar:

Python
>>> print(dir(locals()['__builtins__']))
  • ArithmeticError
  • AssertionError
  • AttributeError
  • BaseException
  • BlockingIOError
  • BrokenPipeError
  • BufferError
  • ChildProcessError
  • ConnectionAbortedError
  • ConnectionError
  • ConnectionRefusedError
  • ConnectionResetError
  • EOFError
  • EnvironmentError
  • Exception
  • FileExistsError
  • FileNotFoundError
  • FloatingPointError
  • GeneratorExit
  • IOError
  • ImportError
  • IndentationError
  • IndexError
  • InterruptedError
  • IsADirectoryError
  • KeyError
  • LookupError
  • MemoryError
  • ModuleNotFoundError
  • NameError
  • NotADirectoryError
  • NotImplementedError
  • OSError
  • OverflowError
  • PermissionError
  • ProcessLookupError
  • RecursionError
  • ReferenceError
  • RuntimeError
  • StopAsyncIteration
  • SyntaxError
  • SystemError
  • TabError
  • TimeoutError
  • TypeError
  • UnboundLocalError
  • UnicodeDecodeError
  • UnicodeEncodeError
  • UnicodeError
  • UnicodeTranslateError
  • ValueError

2.2. Com funcionen les excepcions

Python llança una d'aquestes excepcions en executar una instrucció que provoca un error.

Quan es produeixen aquestes excepcions, l'intèrpret de Python detén l'execució del procés actual i el passa al procés que ha fet la crida, fins que algú la tracte. Si ningún procés la tracta, el programa es detendrà.

Per exemple, considerem un programa en què tenim una funció A que crida a la funció B, que al seu torn crida a la funció C. Si es produeix una excepció a la funció C però no es tracta a C, l’excepció passa a B i després a A.

Si no es gestiona mai, es mostrarà un missatge d'error i el nostre programa s'aturarà de sobte.

3. Capturant excepcions en Python

A Python, les excepcions es poden gestionar mitjançant una sentència try.

L'operació crítica que pot generar una excepció es col·loca dins de la clàusula try. El codi que gestiona les excepcions s’escriu a la clàusula except i s'executarà en produïr-se. Per tant, podem escollir quines operacions es realitzaran una vegada que haguem capturat l'excepció.

Exemple:

Python
# importem el mòdul sys per veure el tipus d'excepció
import sys

randomList = ['a', 0, 2]

for element in randomList:
    try:
        print("Element val ", element)
        r = 1/int(element)
        break
    except:
        print("Oops! Excepció capturada -->", sys.exc_info()[0])
        print("Següent iteració")
        print()
print("L'invers de ", element, "és", r)

Com totes les excepcions hereden de la superclasse Exception, podem reescriure el programa com:

Python
# importem el mòdul sys per veure el tipus d'excepció
import sys

randomList = ['a', 0, 2]

for element in randomList:
    try:
        print("Element val ", element)
        r = 1/int(element)
        break
    except Exception as e:
        print("Oops! Excepció capturada -->", e.__class__)
        print("Següent iteració")
        print()
print("L'invers de ", element, "és", r)

A l'exemple anterior, no hem utilitzat cap excepció específica a la clàusula except.

No és una bona pràctica de programació, ja que capturarà totes les excepcions i gestionarà tots els casos de la mateixa manera. Podem especificar quines excepcions hauria de capturar una clàusula except.

Una clàusula try pot tindre un nombre indeterminat de clàusules except per gestionar diferents excepcions, però, només s'executarà una en cas que es produeixi una excepció.

Podem utilitzar una tupla de valors per especificar diverses excepcions en una clàusula except.

Exemple:

Python
try:
   # fer alguna cosa
   pass

except ValueError:
   # manegem ValueError
   pass

except (TypeError, ZeroDivisionError):
   # manegem múltiples excepcions
   # TypeError i ZeroDivisionError
   pass

except:
   # manegem totes les altres excepcions
   pass

3.1. Try ... except ... finally

La sentència try de Python pot tindre una clàusula final opcional. Aquesta clàusula s’executa independentment de si es produix una excepció o no i s’utilitza generalment per alliberar recursos.

Per exemple, podem estar connectats a un centre de dades remot a través de la xarxa o treballar amb un fitxer o una interfície gràfica d'usuari (GUI). En totes aquestes circumstàncies, hem de netejar recursos abans que el programa ature la seua execució, tant si ho fa de forma controlada com si es para bruscament. Aquestes accions (tancar un fitxer, GUI o desconnectar de la xarxa) es realitzen normalment a la clàusula final.

Exemple:

Python
1
2
3
4
5
try:
   f = open("test.txt",encoding = 'utf-8')
   # operacions amb el fitxer
finally:
   f.close()

4. Llançant excepcions en Python

Les excepcions es generen normalment quan es produeixen errors en temps d'execució, però també podem generar/llançar excepcions manualment mitjançant la paraula reservada raise. Opcionalment, podem passar arguments a l’excepció per aclarir per què s’ha generat aquesta excepció.

Python
import sys
try:
    nombre = int(input("Dona'm un número positiu: "))
    if nombre <= 0:
        raise ValueError(str(nombre) + " no és un número positiu!")
    1/0
except ValueError as ve:
    print("Excepció capturada:", ve)
except:
    print("Unexpected error:", sys.exc_info()[0])
    raise

4.1. Assert

Amb la paraula reservada assert llancem una excepció sempre i quan l'expressió que la segueix s'avalua a Fals. Si s'avalua a True, es continua l'execució del programa de forma seqüencial.

Python
1
2
3
4
5
6
7
8
9
try:
    num = int(input("Introdueix un nombre positiu: "))
    assert num > 0
except AssertionError:
    print("AssertionError: No és positiu!")
except ValueError:
    print ("ValueError: No has introdït un número!")
else:
    print("És positiu")

5. Excepcions definides per l'usuari

De vegades necessitem definir excepcions que no estan disponibles a Python quan es dóna alguna condició. En este cas, hem de crear les nostres propies excepcions. Per a fer-ho, hem de definir noves classes que hereden de Exception, ja siga directa o indirectament. Esta nova excepció que hem creat també podrà ser llançada amb raise.

Python
>>>class CustomError(Exception):
...    pass

>>> raise CustomError
Traceback (most recent call last):
...
__main__.CustomError

>>> raise CustomError("S'ha produït un error")
Traceback (most recent call last):
...
__main__.CustomError: S'ha produït un error

Quan estem desenvolupant un programa gran, és una bona pràctica col·locar totes les excepcions definides per l'usuari que el nostre programa definix en un fitxer separat exceptions.py o errors.py.

5.0.1. Activitat 12

Anem a implementar un xicotet joc per consola. El programa generarà un número aleatori entre 0 i 100 (utilitzeu randint() del mòdul random) i demanarà a l'usuari que introduïsca un número.

Mentre el número siga massa menut, llançarà una excepció ErrorEnterMassaMenut indicant-li-ho. Si per contra és massa gran llançarà ErrorEnterMassaGran.

Si s'introdueix un valor no numèric, es llançarà una excepció de tipus ErrorNoEsEnter.

El joc acabarà quan s'introduïsca l'enter buscat, felicitant a l'usuari.

5.0.2. Activitat 13

Modifica el codi de l'activitat 11 per a que no es produïsquen errors en l'execució, ja siga per introdïur valor no definits per a les funcions, valors que no són numèrics o operacions desconegudes. Controla també que no es produïsquen errors en la lectura/escriptura dels arxius.