Fundamentos do Tratamento de Exceções em Python

Erros de sintaxe, como um loop for incomlpeto, devem ser corrigidos antes de rodar o código:


>>> for i in range(5):
...     pass
...
SyntaxError: expected an indented block

Erros lógicos incluem tentativas de operações inválidas, como concatenar um número com uma string, converter valores não numéricos para inteiro, ou acessar índices inexistentes em coleções.


# Tentativa de soma inválida
result = 10 + "texto"

# Conversão de string não numérica
valor = "abc"
num = int(valor)

# Acesso a índice fora dos limites
lista = ["maçã", "banana"]
item = lista[5]

# Chave inexistente em dicionário
dicionário = {"nome": "Ana"}
valor_chave = dicionário["idade"]

# Atributo inexistente em classe
class MinhaClasse:
    pass
MinhaClasse.x

# Divisão por zero
quotient = 1 / 0

Para aumentar a robustez e a tolerância a falhas do programa, é essencial implementar tratamento de exceções. A estrutura básica envolve os blocos try e except:


try:
    bloco de código a ser monitorado
except TipoDeExceção:
    lógica de tratamento quando a exceção ocorre

Por exemplo:


try:
    print("Início da execução")
    print(variavel_inexistente)  # Isso levanta NameError
    print("Fim da execução")
except NameError as error:
    print("Exceção capturada: %s" % error)
print("Continuação do programa")

# Saída:
# Início da execução
# Exceção capturada: name 'variavel_inexistente' is not defined
# Continuação do programa

Quando o código monitorado pode gerar diferentes tipos de exceções, você pode usar múltiplos blocos except para tratar cada caso separadamente, similar a uma estrutura elif:


try:
    bloco de código a ser monitorado
except NomeExceção1:
    tratamento para NomeExceção1
except IndiceExceção:
    tratamento para IndiceExceção
except ChaveExceção:
    tratamento para ChaveExceção

Exemplo com uma função de conversão:


def converter_para_inteiro(objeto):
    try:
        resultado = int(objeto)
    except ValueError as e:
        print("Erro de valor: %s" % e)
        resultado = None
    except TypeError as e:
        print("Erro de tipo: %s" % e)
        resultado = None
    return resultado

converter_para_inteiro("xyz")  # Erro de valor: invalid literal for int() with base 10: 'xyz'
converter_para_inteiro({"a": 1})  # Erro de tipo: int() argument must be a string, a bytes-like object or a number, not 'dict'

Para tratar múltiplos tipos de exceções com a mesma lógica, agrupe-as em uma tupla:


try:
    bloco de código a ser monitorado
except (NomeExceção, IndiceExceção, TipoExceção):
    tratamento unificado para essas exceções

Para capturar qualquer exceção desconhecida, utilize a classe base Exception:


try:
    bloco de código a ser monitorado
except NomeExceção:
    tratamento específico
except Exception:
    tratamento genérico para outras exceções

O bloco else pode ser adicionado após os except e é executado somente se nenhuma exceção ocorrer:


try:
    bloco de código a ser monitorado
except TipoExceção1:
    pass
except TipoExceção2:
    pass
else:
    código a executar quando não há exceções

O bloco finally é sempre executado, independentemente de exceções, e é útil para liberar recursos:


try:
    bloco de código a ser monitorado
except TipoExceção:
    pass
else:
    código sem exceções
finally:
    código sempre executado (ex.: fechar arquivos ou conexões)

Exemplo:


arquivo = None
try:
    arquivo = open("dados.txt", "r", encoding="utf-8")
    conteudo = arquivo.read().strip()
    numero = int(conteudo)  # Pode levantar ValueError se conteudo não for numérico
finally:
    if arquivo is not None:
        arquivo.close()

Para violar regras definidas pelo programador, use a instrução raise para levantar exceções explicitamente:


class Pessoa:
    def __init__(self, nome, idade):
        if not isinstance(nome, str):
            raise TypeError("nome deve ser uma string")
        if not isinstance(idade, int):
            raise TypeError("idade deve ser um inteiro")
        self.nome = nome
        self.idade = idade

pessoa1 = Pessoa(12345, 30)  # TypeError: nome deve ser uma string
pessoa2 = Pessoa("Carlos", "trinta")  # TypeError: idade deve ser um inteiro

Exceções personalizadas podem ser criadas herdando de classes de exceção embutidas:


class ErroDeRecursoExaurido(Exception):
    def __init__(self, mensagem="O recurso foi esgotado"):
        super().__init__()
        self.mensagem = mensagem

    def __str__(self):
        return "Exceção: %s" % self.mensagem

class ErroDeRede(IOError):
    pass

raise ErroDeRecursoExaurido  # Exceção: O recurso foi esgotado
raise ErroDeRede("Falha na conexão")  # Exceção: Falha na conexão

A instrução assert verifica se uma condição é verdadeira; caso contrário, levanta AssertionError:


idade = "vinte"

assert isinstance(idade, int)  # Levanta AssertionError se idade não for int

# Equivalente a:
if not isinstance(idade, int):
    raise AssertionError

O uso de tratamento de exceções deve ser equiilbrado. Para erros previsíveis, utilize estruturas condicionais para prevenção:


entrada = input("Digite sua idade: ").strip()
if entrada.isdigit():
    idade = int(entrada)
else:
    print("Entrada inválida: insira um número.")

Para situações imprevisíveis, como falhas de rede, o tratamento de exceções é apropriado:


import requests
from requests.exceptions import ConnectTimeout

def obter_conteudo(url):
    try:
        resposta = requests.get(url, timeout=3)
        conteudo = resposta.text
    except ConnectTimeout:
        print("Tempo de conexão esgotado.")
        conteudo = None
    except Exception:
        print("Erro de rede inesperado.")
        conteudo = None
    return conteudo

obter_conteudo("https://www.example.com")

Tags: Python Exceções tratamento-de-erros try-except raise

Publicado em 6-9 06:03 por Thomas