Exceções em Python – parte 3

excecoes_em_python-3_abertura

Dando sequência com as exceções em Python, na parte anterior foi visto como refinar o tratamento delas, seja com o uso de estruturas como else e finally, pela recuperação de maiores detalhes sobre o que aconteceu e do uso do raise para forçar (ou invocar) a ocorrência de uma determinada exceção.

Nesta parte, como criar e utilizar sua própria exceção.

Criando sua própria exceção

Em Python todas as exceções são construídas a partir da classe BaseException, porém para criação de exceções customizadas a recomendação é utilizar a classe Exception.

class MinhaExcecaoError(Exception):
    pass

Esta é uma construção bem simples e cria uma nova exceção — MinhaExcecaoError — a partir da classe Exception e herdando tudo mais dela, inclusive o construtor. E para utilizá-la basta usar o comando raise

raise MinhaExcecaoError

Ou, desejando ser um pouco mais explícito, acrescentando uma mensagem detalhando o que ocorreu.

raise MinhaExcecaoError("Aconteceu um erro aqui!")

E claro, sem esquecer do bloco try-except

try:
    erro = False
    # ...
    if erro:
        raise MinhaExcecaoError("Ocorreu um erro!")

except MinhaExcecaoError as mensagem:
    print(mensagem)
    exit(1)

Para fazer o devido tratamento dela dentro do programa! 🙂

Um outro exemplo

Agora algo um pouco mais complexo e também mais funcional. Considere a seguinte estrutura hierárquica:

País
 ╰─┈ Região
      ╰─┈ Estado
           ╰─┈ Município

Que foi codificada em um arquivo de texto da seguinte maneira:

1:Região
2:Estado
3:Município
3:Município
2:Estado
3:Município
...

Ou seja, o número do lado esquerdo indica seu nível na estrutura enquanto que seus vizinhos sua posição. Assim, montei uma classe contendo um método para interpretar este arquivo de entrada e recriar a estrutura original — mas este sujeito não é importante… 🙂

O importante mesmo é a exceção customizada para tratar os erros do arquivo.

class ParseError(Exception):
    def __init__(self, mensagem, linha=0):
        self.mensagem = mensagem
        self.linha = linha

    def __str__(self):
        return "Erro: {}".format(self.mensagem) + \
            (" na linha {}!".format(self.linha) \
            if self.linha > 0 else "!")

Que será chamada em duas situações específicas, a primeira no caso da hierarquia estar incorreta (o nível de um item lido não for menor ou igual que o nível atual acrescido de um).

raise ParseError("Nível hierárquico inválido", linha)

Assim…

$ python3 municipios.py 1_nivel_hierarquico_invalido.txt 
Erro: Nível hierárquico inválido na linha 4!

Ou no caso o nível não fazer parte das hierarquias válidas.

raise ParseError("Hierarquia incorreta", linha)

Então…

$ python3 municipios.py 2_hierarquia_incorreta.txt 
Erro: Hierarquia incorreta na linha 2!

A exceção também será invocada no construtor da classe no caso do arquivo de entrada não existir.

raise ParseError("Arquivo não encontrado") from FileNotFoundError

Ou seja…

$ python3 municipios.py este_arquivo_nao_existe.txt
Erro: Arquivo não encontrado!

Esta sintaxe indica que a exceção invocada “ParseError” (a causa) ocorreu em decorrência de uma outra, a “FileNotFoundError” (contexto) e é exclusiva da versão 3.x do Python e para fazer que o programa funcione na versão 2.x, remova o “from FileNotFoundError” da linha.

E ao executar o programa utilizando um arquivo contendo dados válidos, o resultado será a lista de municípios fluminenses.

excecoes_em_python-3_municipios_fluminenses

Mas você pode alterar para qualquer outra unidade da federação… 🙂

Considerações finais

Este é o fim deste “bate-papo” sobre o uso de exceções em Python contemplando desde o básico, o bloco try-except, passando pela identificação e detalhamento das exceções e finalizando com o uso de exceções customizadas para utilizar em seu programa ou módulo. E lembrando que os arquivos usados nos exemplos acima estão no repositório Git deste blog no GitHub.

Anúncios