Controle de Exceções – try/except/else/finally


Quando programamos, temos sempre que nos preocupar com os erros que podem acontecer no programa. Na minha visão temos 2 tipos de erros: os que esperamos e os que NÃO esperamos ! Os que experamos são aqueles error que sabemos que vão acontecer em um dado momento, que programamos para que fosse assim, ou que sabemos das variações que podem ocorrer em algum tipo de dado/informação esperado, e então controlamos e os outros todos são os que podem acontecer no meio do caminho, como problemas de rede, problemas de banco de dados, problemas de permissão, e por ai vai… Também se formos realmente tentar prever e tratar cada erro que pode ocorrer durante a execução do nosso programa, nossa, vão ser 2/3 de programação só para isto… hehehe

O Python, como uma ótima e completa linguagem que é, tem um ótimo sistema de exceções, tanto para controlá-las como para criar nossos próprios error ( Exceptions ).

Vejamos alguns exemplo que irei explicar e você vai entender, os quais foram tirados justamente do tutorial oficial do Python:
Link: http://docs.python.org/tutorial/errors.html

Basicamente o tratamento de erros no Python é feito com duas expressões: try e except.

try:
    i = 1/0
except:
    print "Ops, Erro!"

Simples.
Isto é o básico para não deixar nosso programa terminar sem uma explicação e pegar qualquer erro que ocorra.

Mas no except podemos expecificar o erro, desta forma:

try:
    i = 1/0
except ZeroDivisionError:
    print "Ops, Erro!"

Assim, definimos que estamos tratando apenas o erro de divisão por zero!
Ok, mas e quando precisamos tratar vários erros ?

Podemos fazer assim:

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except IOError:
    print "I/O error"
except ValueError:
    print "Could not convert data to an integer."

especificando cada erro que queremos tratar em uma seção de except, ou:

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
except (IOError, ValueError):
    print "Erro esperado"

Definindo uma lista de erros para serem tratados de uma mesma forma, na mesma seção de except.
Ok, mas e agora como eu pego as informações do erro ?

Bom, podemos definir uma variável para o erro, assim:

try:
    i = 1/0
except ZeroDivisionError as detail:
    print 'Handling run-time error:', detail

Assim, conseguimos buscas as informações do erro com a variável “detail”.
Vejam abaixo:

import sys

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
    b = i/0
except IOError as (errno, strerror):
    print "I/O error({0}): {1}".format(errno, strerror)
except ValueError as erro:
    print "Could not convert data to an integer."
    print "ERRO:", erro
except ZeroDivisionError:
    print "ERRO: Divisão por zero"
except (NameError, ValueError):
    print "Erros estranhos acontecendo!"
except:
    print "Unexpected error:", sys.exc_info()[0]
    raise

Temos um exemplão mais completo, mostrando como :

  • Capturar qualquer erro
  • Capturar erros específicos
  • Capturar vários erros na mesma seção
  • Capturar as informações dos erros

Porém neste trecho de código temos alguns detalhes diferentes, não citados acima:

  • o “sys.exc_info”, que mostra algumas informações sobre o ocorrido erro
  • o “raise”, que joga a exceção para cima, ou seja, que ela seja levada até o proximo try/except ou o método chamador, etc…
  • e as variáveis “errno” e “strerror”, no item do IOError: Isto é pq cada tipo de erro retorna um tipo de informação, que geralmente é a mensagem, mas neste caso, por exemplo, ele pode retornar uma tupla com o código do erro também.

Veja que em ambos os casos funciona:

except IOError as (errno, strerror):
    print "I/O error({0}): {1}".format(errno, strerror)
#ou
except IOError as erro:
    print "I/O error:", erro

Mas, além disto tudo, temos mais dois itens interessantes, e que podem ser muito úteis também:

  • else = É executado sempre que NÃO ocorrer um erro no try/except, veja:
try:
    f = open(arg, 'r')
except IOError:
    print 'cannot open', arg
else:
    print arg, 'has', len(f.readlines()), 'lines'
    f.close()

Isto garante que aquele código não execute quando ocorrer erro!

  • finally = É executado SEMPRE, ocorrendo ou não ocorrendo erro, veja:
print "Iniciado o processo!"
try:
    f = open("myfile.txt", 'r')
except IOError:
    print 'cannot open', arg
else:
    print arg, 'has', len(f.readlines()), 'lines'
    f.close()
finally:
    print "Finalizado o processo!"

Claro, que este é um exemplo muito simples, mas as vezes precisamos deste ponto para controles mais elaborados.
Então, completando nosso exemplão fica assim:

import sys

try:
    f = open('myfile.txt')
    s = f.readline()
    i = int(s.strip())
    b = i/2
except IOError as (errno, strerror):
    print "I/O error({0}): {1}".format(errno, strerror)
except ValueError as erro:
    print "Could not convert data to an integer."
    print "ERRO:", erro
except ZeroDivisionError:
    print "ERRO: Divisão por zero"
except:
    print "Unexpected error:", sys.exc_info()[0]
    raise
else:
    f.close()
    print "Ocorreu tudo ok! Arquivo fechado!"
finally:
    print "Finalizado!"

Ok !? Capatarm ? Qualquer dúvida podem comentar…
E por hoje é só pessoal ! Até mais.

Anúncios

7 Comments

  1. Bom tutorial, realmente me ajudou, mas sabe me dizer como fazer um try infinito enquanto houver erro? tipo, quero q a pesoa digite um float e ela digita uma letra, aí ele pede denovo pra ela digitar um float e ela digita uma string, e dá o erro, como fazer pra nunca dar esse erro?

    Curtir

    Responder

  2. wauuuu! professor foi pra mim um grande suporte na minha investigação,mas tenho uma dúvida quando é que usamos o finally?e qual é a sua finalidade?

    Curtir

    Responder

  3. Olá, muito bom o post, me ajudou muito. Só que tenho uma dúvida: se o construtor de minha classe gerar uma exceção, qual o procedimento comum a ser tomado? Eu pensei em colocar um sys.exit mas aí fecharia a aplicação toda. Pensei também em tratar o erro no próprio construtor com try/except, mas aí o restante do código ainda assim era executado. O que estou fazendo é não tratar as exceções na classe e deixar pra quem tá chamando tratar. Seria esse um procedimento adequado? Quando isso ocorre, o que o Sr. utiliza?

    Curtir

    Responder

    1. Bom, isto é um ponto bastante relativo ao que você deseja no seu programa, inclusive acho que a sua solução foi a mais acertada neste caso. O que você pode fazer as vezes é tratar os erros e retornar um erro customizado pelo seu programa, assim padronizando o tratamento. Fora que qdo você fizer o raise do erro no construtor a instanciação da classe vai ser cancelada.

      E sobre este blog, ele está parado, e agora está em novo endereço: pythonrs.org.br. Convido você a se cadastrar para receber as novas postagens também lá.

      Curtir

      Responder

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

w

Conectando a %s