6. As exceções
Vamos agora nos concentrar nas exceções.
![]() |
O primeiro script ilustra a necessidade de gerenciar exceções.
# -*- coding=utf-8 -*-
# ocorre um erro
x=4/0
Provocamos deliberadamente um erro para observar as informações geradas pelo interpretador. O resultado na tela é o seguinte:
A linha 4 nos fornece:
- o tipo da exceção: ZeroDivisionError;
- a mensagem de erro associada: divisão de inteiros ou módulo por zero. Ela está em inglês. Isso é algo que talvez queiramos alterar.
A regra fundamental na programação é que devemos fazer de tudo para evitar falhas “inesperadas”, como a mencionada acima. Mesmo em caso de erro, o programa deve ser encerrado de forma adequada, fornecendo informações sobre o erro que ocorreu.
A sintaxe para o tratamento de exceções é a seguinte:
try:
actions susceptibles de lancer une exception
except [classe d'exception, ...]:
actions de gestion de l'exception
finally:
actions toujours exécutées qu'il y ait exception ou non
No bloco **try**, a execução das ações é interrompida assim que ocorre uma exceção. Nesse caso, a execução prossegue com as ações da cláusula **except**.
A cláusula
except [MyException, ...]:
intercepta exceções do tipo MyException ou derivadas. Quando ocorre uma exceção em um try, o interpretador examina as cláusulas except associadas ao **try na ordem em que foram escritas. Ele para na primeira cláusula except capaz de tratar a exceção que ocorreu. Se não encontrar nenhuma, a exceção é repassada para o método chamador. Se este tiver um bloco** **try/except**, a exceção é novamente tratada; caso contrário, ela continua subindo pela cadeia de métodos chamados. Em última instância, ela chega ao interpretador Python. Este, então, interrompe o programa em execução e exibe uma mensagem de erro do tipo mostrado no exemplo anterior. A regra, portanto, é que o programa principal deve interceptar todas as exceções que possam ser propagadas pelos métodos chamados.
Uma exceção traz consigo informações sobre o erro que ocorreu. É possível obtê-las com a seguinte sintaxe:
except MyException as informations:
informações é uma tupla que contém as informações relacionadas à exceção.
A sintaxe
except MyException, erreur:
atribui à variável erreur a mensagem de erro relacionada à exceção.
Para lançar uma exceção, utiliza-se a sintaxe
raise MyException(param1, param2, ...)
, em que, na maioria das vezes, MyException é uma classe derivada da classe Exception. Os parâmetros passados ao construtor da classe estarão disponíveis na cláusula except das estruturas de interceptação de exceções.
Esses conceitos são ilustrados pelo script a seguir.
O script a seguir lida explicitamente com os erros:
# -*- coding=utf-8 -*-
i=0
# provoca-se um erro e ele é tratado
x=2
try:
x=4/0
except ZeroDivisionError, erreur:
print ("%s : %s ") % (i, erreur)
# o valor de x não mudou
print "x=%s" % (x)
# repetimos o processo
i+=1
try:
x=4/0
except Exception, erreur:
# intercepta-se a exceção mais geral
print ("%s : %s ") % (i, erreur)
# é possível interceptar vários tipos de exceções
i+=1
try:
x=4/0
except ValueError, erreur:
# essa exceção não ocorre aqui
print ("%s : %s ") % (i, erreur)
except Exception, erreur:
# interceptamos a exceção mais geral
print ("%s : (Exception) %s ") % (i, erreur)
except ZeroDivisionError, erreur:
# intercepta-se um tipo específico
print ("%s : (ZeroDivisionError) %s ") % (i, erreur)
# repetimos o processo alterando a ordem
i+=1
try:
x=4/0
except ValueError, erreur:
# essa exceção não ocorre aqui
print ("%s : %s ") % (i, erreur)
except ZeroDivisionError, erreur:
# intercepta-se um tipo específico
print ("%s : (ZeroDivisionError) %s ") % (i, erreur)
except Exception, erreur:
# intercepta-se a exceção mais geral
print ("%s : (Exception) %s ") % (i, erreur)
# uma cláusula `except` sem argumentos
i+=1
try:
x=4/0
except:
# não nos interessamos pela natureza da exceção nem pela mensagem de erro
print ("%s : il y a eu un probleme ") % (i)
# outro tipo de exceção
i+=1
try:
x=int("x")
except ValueError, erreur:
print ("%s : %s ") % (i, erreur)
# uma exceção transporta informações em uma tupla acessível ao programa
i+=1
try:
x=int("x")
except ValueError as infos:
print ("%s : %s ") % (i, infos)
# é possível lançar exceções
i+=1
try:
raise ValueError("param1","param2","param3")
except ValueError as infos:
print ("%s : %s ") % (i, infos)
# é possível criar suas próprias exceções
class MyError(Exception):
pass
# lança-se a exceção MyError
i+=1
try:
raise MyError("info1","info2", "info3")
except MyError as infos:
print ("%s : %s ") % (i, infos)
# lança-se a exceção MyError
i+=1
try:
raise MyError("mon msg d'erreur")
except MyError, erreur:
print ("%s : %s ") % (i, erreur)
# é possível lançar qualquer tipo de objeto
class Objet:
def __init__(self,msg):
self.msg=msg
def __str__(self):
return self.msg
i+=1
try:
raise Objet("pb...")
except Objet as erreur:
print "%s : %s" % (i, erreur)
# a cláusula finally é sempre executada
# haja ou não uma exceção
i+=1
x=None
try:
x=1
except:
print "%s : exception" % (i)
finally:
print "%s : finally x=%s" % (i,x)
i+=1
x=None
try:
x=2/0
except:
print "%s : exception" % (i)
finally:
print "%s : finally x=%s" % (i,x)
Notas:
- linhas 6-9: trata-se de uma divisão por zero;
- linha 8: intercepta-se a exceção exata que ocorre;
- linha 11: devido à exceção ocorrida, x não recebeu nenhum valor e, portanto, não sofreu alteração;
- linhas 15-19: repetimos o mesmo procedimento, mas interceptando uma exceção de nível superior do tipo Exception. Como a exceção ZeroDivisionError deriva da classe Exception, a cláusula except irá interrompê-la;
- linhas 23-33: são definidas várias cláusulas except para lidar com diversos tipos de exceção. Apenas uma cláusula except será executada, ou nenhuma, se a exceção não atender a nenhuma cláusula “except”;
- linhas 51-55: a cláusula except pode não ter nenhum argumento. Nesse caso, ela interrompe todas as exceções;
- linhas 59-62: introduzem a exceção ValueError;
- linhas 66-69: recuperam-se as informações transportadas pela exceção;
- linhas 73-76: apresentam a maneira de lançar uma exceção;
- linhas 79-84: ilustram o uso de uma classe de exceção proprietária MyError;
- linhas 79-80: a classe MyError limita-se a derivar da classe base Exception. Ela não acrescenta nada à sua classe base. Mas agora pode ser nomeada explicitamente nas cláusulas
except; - linhas 97-107: ilustram que, em Python, é possível lançar qualquer tipo de objeto, e não apenas objetos derivados da classe Exception;
- linhas 109-127: ilustram o uso da cláusula finally.
Os resultados na tela são os seguintes:
0 : integer division or modulo by zero
x=2
1 : integer division or modulo by zero
2 : (Exception) integer division or modulo by zero
3 : (ZeroDivisionError) integer division or modulo by zero
4 : il y a eu un probleme
5 : invalid literal for int() with base 10: 'x'
6 : invalid literal for int() with base 10: 'x'
7 : ('param1', 'param2', 'param3')
8 : ('info1', 'info2', 'info3')
9 : mon msg d'erreur
10 : pb...
11 : finally x=1
12 : exception
12 : finally x=None
Este novo script ilustra a propagação de exceções na cadeia de métodos chamadores:
# -*- coding=utf-8 -*-
# uma exceção proprietária
class MyError(Exception):
pass
# três métodos
def f1(x):
# não se lida com exceções — elas são repassadas automaticamente
return f2(x)
def f2(y):
# não se trata das exceções — elas são repassadas automaticamente
return f3(y)
def f3(z):
if (z % 2) == 0:
# se z for par, lança-se uma exceção
raise MyError("exception dans f3")
else:
return 2*z
#---------- main
# as exceções sobem pela cadeia de métodos chamados
# até que um método as intercepte. Aqui, será o método `main`
try:
print f1(4)
except MyError as infos:
print "type :%s, arguments : %s" % (type(infos),infos)
# um método pode enriquecer as exceções que ele reenvia
def f4(x):
try:
return f5(x)
except MyError as infos:
# enriquecemos a exceção e, em seguida, a reenviamos
raise MyError(infos,"exception dans f4")
def f5(y):
try:
return f6(y)
except MyError as infos:
# enriquecemos a exceção e, em seguida, a relançamos
raise MyError(infos, "exception dans f5")
def f6(z):
if (z % 2) == 0:
# lança-se uma exceção
raise MyError("exception dans f6")
else:
return 2*z
#---------- main
try:
print f4(4)
except MyError as infos:
print "type :%s, arguments : %s" % (type(infos),infos)
Notas:
- linhas 27-30, na chamada main --> f1 --> f2 --> f3 (linha 28), a exceção MyError lançada por f3 será propagada até main. Ela será então tratada pela cláusula except da linha 29;
- linhas 55-58: na chamada main --> f4 --> f5 --> f6 (linha 56), a exceção lançada MyError por f6 será propagada até main. Ela será então tratada pela cláusula except da linha 29. Desta vez, ao subir pela cadeia de métodos chamadores, a exceção MyError é enriquecida com informações adicionadas por cada método percorrido.
Os resultados na tela são os seguintes:
