Tratamento de exceções

Uma exceção ocorre quando algo inesperado acontece em algum programa, por exemplo, ao ler um texto e converter o mesmo para um número pode gerar uma exceção caso o texto lido não seva um valor numérico. Toda vez que uma exeção ocorre no python a mesma é apresentada no terminal, mostrando o que aconteceu de errado. Alé disto, o programa para de executar.

A seguir um exemplo de uma exceção:

In [3]:
lido = raw_input("Digite um numero: ")
valor = float(lido)
print valor
Digite um numero: dez
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-3-66bbec44bbfe> in <module>()
      1 lido = raw_input("Digite um numero: ")
----> 2 float(lido)

ValueError: could not convert string to float: dez

Observe que ao digitar o texto dez e tentar converter o mesmo para float gera uma exeção. E o programa é incerrado, ou seja o print na sequencia do código nunca vai ser executado caso haja uma exceção.

Como você ja deve ter notado, um programa que encerra do nada é muito chato de ser utilizado, principalmente pq nós humanos cometemos erros e, portanto, podemos informar dados erroneamente. Portanto é importante termos uma ferramenta que nos possibilite tratar estas exceções, de forma que o programa não pare de executar. É importante frizar que podem ocorrer inumeros tipos de exceções diferentes e não apenas de entrada de dados.

No python, e na maioria das linguagens de programação, o tratamento de exeções é feito com o comando try e o comando except. Estes comandos permitem ao programador tratar as exceções q possam vir a ocorrer.

O comando try serve para indicar que desejamos tentar executar um comando que possa gerar uma execção, por exemplo, converter um texto para número. O try possui um bloco de código assim como o if e outros comandos que ja vimos até aqui, todos os comandos que estiverem no bloco do try ao dispararem uma exeção irão para o except. O except é onde tratamos a exceção, ou seja, caso de algum erro dentro do try, podemos tratar o erro dentro do except.

Por exemplo, vamos tentar tratar o erro de converção de uma string para número.

In [6]:
valorLido = raw_input("Digite um numero: ")

try:
    valorLido = float(valorLido)
except Exception:
    print "você não informou um número"
    
print valorLido
Digite um numero: dfsdfke
você não informou um número
dfsdfke

Observe que ao digitar um valor não numérico não vai ser possível converter o valor para float. Desta forma gera-se uma exceção a qual pode ser taratada no exept. Agora não temos mais aquele erro que apareceu no exemplo anterior.

Você notou que ao lado do except esta escrito Exception? ao lado do except nós informamos qual tipo de execeção queremos tratar, quando usamos Exception estamos dizendo ao python que aquele except vai tratar qualquer tipo de exceção possível. Estretanto as vezes um trecho de código pode gerar diferentes tipos de exceções e nem sempre queremos tratar todas as exceções no mesmo lugar pois elas podem ter lógicas diferentes.

Vamos começar com um exemplo simples, em vez de colocar Exception no except vamos dizer ao except para tratar apenas a exceção que é gerada quando há um erro de conversão. Mas como saber qual é a exceção? Temos duas formas: 1- olhar na documentação do comando que estamos utilizando; ou, 2- gerar a exceção e procurar ela no terminal.

Vamos ver a forma 2, a seguir geramos a exceção:

In [7]:
float("vai dar caca")
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-7-ccd9bcdd63d8> in <module>()
----> 1 float("vai dar caca")

ValueError: could not convert string to float: vai dar caca

Podemos identificar a exceção pelo texto em vermelho. Neste caso, ValueError. E agora podemos tratar especificamente esta exceção.

In [8]:
valorLido = raw_input("Digite um numero: ")

try:
    valorLido = float(valorLido)
except ValueError:
    print "você não informou um número"
    
print valorLido
Digite um numero: huehue
você não informou um número
huehue

Obeserve que na pratica não fez muita diferença, mas isso se deve ao fato de que só vamos ter uma exceção ocorredo, e se tivermos duas Por exemplo, podemos fazer um programa que lê um numero do teclado e usamos esse numero para fazer uma divisão. Lembre que uma divisão por 0 não existe.

Exemplo:

In [11]:
try:
    num = int(raw_input("digite o divisor: "))
    resultado = 100/num
    print resultado
except ValueError:
    print "você não digitou um número!"
except ZeroDivisionError:
     print "zero nÃo é um divisor valido"
except Exception:
    print "ocorreu uma exceção desconhecida"
digite o divisor: 0
zero nÃo é um divisor valido

Agora conseguimos tratar o erro de divisão e de escrita errada separadamente.

Podemos melhorar esse programa, no caso, enquanto o usuário não digitar um valor valido, vamos repetir a leitura.

In [12]:
while True:
    try:
        num = int(raw_input("digite o divisor: "))
        resultado = 100/num
        print resultado
        break
    except ValueError:
        print "você não digitou um número!"
    except ZeroDivisionError:
         print "zero nÃo é um divisor valido"
    except Exception:
        print "ocorreu uma exceção desconhecida"
digite o divisor: 0
zero nÃo é um divisor valido
digite o divisor: zero
você não digitou um número!
digite o divisor: dez
você não digitou um número!
digite o divisor: 10
10
In [ ]: