Tratamento de Exceções em Python: Guia Completo com Exemplos

Em Python, a construção try except é utilizada para gerenciar exceções de maneira eficaz, evitando que o programa termine abruptamente. O tratamento de exceções eleva a robustez do código, tornando-o mais resistente a falhas. Este guia aborda o tratamento de exceções, indicando cenários ideais para sua aplicação, e oferece um bônus sobre como gerar exceções.

O que é o Tratamento de Exceções?

Exceções são eventos inesperados, erros críticos que surgem durante a execução de um programa. Se não forem tratadas, essas exceções levam ao encerramento do programa. O tratamento de exceções é, portanto, uma estratégia para lidar com esses imprevistos, garantindo que o programa continue funcionando mesmo diante de problemas.

Um exemplo prático ajuda a ilustrar o conceito de exceção:

user_input = input("Digite um número: ")
num = int(user_input)
print("O dobro do seu número é:", num * 2)

A princípio, o programa parece perfeito: solicita uma entrada do usuário, converte-a para um número inteiro e exibe o dobro do valor inserido.

Ao executar o programa e inserir o número 5, tudo funciona como esperado. Veja abaixo:

Contudo, se repetirmos o processo, mas, em vez de um número, inserirmos a palavra “olá”, o programa apresentará uma falha. A string “olá” não pode ser convertida para um número inteiro, gerando uma exceção que finaliza o programa.

Por que Exceções Acontecem e Por Que Devo Tratá-las?

Exceções são comuns porque, ao programar, dividimos as tarefas em funções. Essas funções são acionadas para realizar diversas operações.

No exemplo anterior, usamos a função input para obter a entrada do usuário, depois a função int para converter a entrada em um inteiro e, por último, a função print para exibir o resultado.

No entanto, ao executar suas tarefas, as funções podem encontrar erros que não sabem como resolver. Nesse caso, a função para de funcionar e sinaliza que um erro ocorreu, levantando uma exceção.

O código que chamou a função é responsável por escutar essas exceções e agir adequadamente. Caso contrário, o programa falhará ao encontrar um erro, como visto no exemplo.

Assim, as exceções são um mecanismo de comunicação que permite que uma função sinalize um erro para o código que a chamou. A reação a essa sinalização é o que chamamos de tratamento de exceções.

Tipos Diferentes de Exceções

É crucial entender que nem todas as exceções são iguais. Diferentes erros resultam em diferentes tipos de exceções. Por exemplo, tentar dividir um número por zero gera um ZeroDivisionError. Tentar realizar uma operação com um tipo de dado incorreto gera um TypeError. A lista completa de exceções em Python é vasta e detalhada.

Como Tratar Exceções

Como já explicado, as exceções são como sinais de socorro emitidos pelas funções. Nosso código precisa “ouvir” esses sinais e reagir de forma apropriada. Para isso, usamos a construção try except do Python. A estrutura básica dessa construção é:

try:
    # Código que pode gerar uma exceção
except:
    # Código a ser executado se uma exceção ocorrer
finally:
    # Código que é executado sempre, com ou sem exceção

A construção é formada por três palavras-chave:

try

A palavra-chave try inicia a construção try except e marca um bloco de código que pode gerar uma exceção. É uma ordem para o Python tentar executar o código nesse bloco. Se uma exceção ocorrer, a execução para e o código no bloco except é acionado.

except

A palavra-chave except marca o bloco de código que será executado caso uma exceção ocorra durante a execução do bloco try. É possível definir vários blocos except para diferentes tipos de exceções. Isso será detalhado adiante.

finally

A palavra-chave finally é a última parte da construção try except. Marca um bloco de código que será executado sempre, independentemente de uma exceção ter ocorrido ou não.

Um Exemplo

O exemplo a seguir demonstra como as palavras-chave try, except e finally atuam no tratamento de uma exceção. Vamos modificar o exemplo anterior:

try:
    user_input = input("Digite um número: ")
    num = int(user_input)
    print("O dobro do seu número é:", num * 2)
except:
    print("Algo deu errado")
finally:
    print("Este código será executado de qualquer forma")

Ao executar o código com uma entrada válida (como 5), o resultado será:

Se a entrada for “olá”, o resultado será:

Quando não há exceção no bloco try, o programa executa o bloco finally. Se houver uma exceção no bloco try, o programa executa o bloco except, seguido do bloco finally.

É possível tratar exceções de tipos específicos. Para tratar ValueError e KeyboardInterrupt de forma distinta, modifique o código:

try:
    user_input = input("Digite um número: ")
    num = int(user_input)
    print("O dobro do seu número é:", num * 2)
except ValueError:
    print("O valor não pode ser convertido para inteiro")
except KeyboardInterrupt:
    print("Interrupção por teclado recebida")
except:
    print("Bloco genérico de exceções")
finally:
    print("Este código será executado de qualquer forma")

Neste código, temos três blocos except. O primeiro trata ValueError, o segundo, KeyboardInterrupt, e o último, sem tipo de exceção especificado, captura todas as demais exceções.

A saída ao executar o código será algo como:

Ao ocorrer uma exceção, você pode obter informações adicionais sobre ela. Para acessar o objeto da exceção, use a palavra-chave as:

try:
    user_input = input("Digite um número: ")
    num = int(user_input)
    print("O dobro do seu número é:", num * 2)
except ValueError as e:
    print("Erro de valor:", e)
except KeyboardInterrupt as e:
    print("Interrupção por teclado:", e)
except Exception as e:
    print("Outra exceção:", e)

Como Gerar Exceções

Até agora, tratamos exceções geradas por outras funções. No entanto, também podemos gerar exceções no nosso código. Para isso, usamos a palavra-chave raise, especificando o tipo de exceção e uma mensagem descritiva.

No exemplo a seguir, usamos a classe Exception para gerar uma exceção genérica:

raise Exception('Algo deu errado')

A execução deste trecho resulta em:

Também é possível especificar diferentes tipos de exceções. Por exemplo, gerar um TypeError para um valor de tipo incorreto:

def double(x):
    if isinstance(x, int):
        return x * 2
    else:
        raise TypeError('x deve ser um inteiro')

Ou gerar um ValueError para um valor fora dos limites:

def say_hello(name):
    if name == '':
        raise ValueError('Valor fora dos limites')
    else:
        print('Olá', name)

Você pode criar seus próprios tipos de exceção, herdando da classe Exception. Exemplo:

class InvalidHTTPMethod(Exception):
    pass

Podemos usar esta classe para gerar exceções:

raise InvalidHTTPMethod('Deve ser GET ou POST')

Casos de Uso Comuns

O tratamento de exceções é útil em muitas situações. Além do exemplo com entradas de usuários, é crucial ao lidar com requisições de rede e ao ler arquivos.

Requisições de Rede

O código a seguir faz uma requisição ao Google, com tratamento de exceções da biblioteca requests:

import requests

try:
    response = requests.get("https://google.com")

    if 200 <= response.status_code < 300:
        print("Requisição bem-sucedida!")
    else:
        print(f"Requisição falhou com status: {response.status_code}")
except requests.exceptions.RequestException as e:
    print(f"RequestException: {e}")
except requests.exceptions.ConnectionError as e:
    print(f"ConnectionError: {e}")
except requests.exceptions.Timeout as e:
    print(f"Timeout: {e}")
except requests.exceptions.TooManyRedirects as e:
    print(f"TooManyRedirects: {e}")
except requests.exceptions.HTTPError as e:
    print(f"HTTPError: {e}")
except Exception as e:
    print(f"Erro inesperado: {e}")

Leitura de Arquivos

O exemplo abaixo lê dados de um arquivo chamado “hello.txt”, tratando FileNotFoundError e IOError:

try:
    with open(file_path, 'r') as file:
        data = file.read()
        print("Conteúdo do arquivo:")
        print(data)
except FileNotFoundError as e:
    print(f"FileNotFoundError: {e}")
except IOError as e:
    print(f"IOError: {e}")
except Exception as e:
    print(f"Erro inesperado: {e}")

Conclusão

Este artigo explorou o conceito de exceções, suas causas e a importância de tratá-las. Vimos como o tratamento de exceções torna o código mais robusto e confiável, evitando travamentos. Além disso, aprendemos como lidar com exceções e como gerá-las em nossos próprios códigos.

Para aprofundar seus conhecimentos, explore os tipos comuns de erros em Python e como resolvê-los.