---
title: "Tratamento de Erros em Python — 2025 | Python Brasil"
url: "https://python.dev.br/blog/tratamento-de-erros-python/"
markdown_url: "https://python.dev.br/blog/tratamento-de-erros-python.MD"
description: "Domine o tratamento de erros em Python com try/except, exceções customizadas e boas práticas. Aprenda agora!"
date: "2026-01-10"
author: "Equipe Python Brasil"
---

# Tratamento de Erros em Python — 2025 | Python Brasil

Domine o tratamento de erros em Python com try/except, exceções customizadas e boas práticas. Aprenda agora!


Erros fazem parte do desenvolvimento de software. A diferença entre um programa amador e um profissional está em como esses erros são tratados. Python possui um sistema robusto de exceções que permite capturar, tratar e até criar seus próprios tipos de erro, garantindo que seu programa se comporte de maneira previsível mesmo em situações inesperadas.

Neste artigo, vamos explorar desde o básico do try/except até técnicas avançadas como exceções personalizadas e padrões de tratamento de erros usados em projetos profissionais.

## Entendendo exceções em Python

Uma exceção é um evento que interrompe o fluxo normal de execução do programa. Quando algo dá errado, Python levanta (raises) uma exceção. Se ela não for tratada, o programa encerra com uma mensagem de erro.

```python
# Exemplos de exceções comuns
# print(10 / 0)              # ZeroDivisionError
# print(int("abc"))           # ValueError
# lista = [1, 2, 3]
# print(lista[10])            # IndexError
# dicionario = {"a": 1}
# print(dicionario["b"])      # KeyError
# import modulo_inexistente   # ModuleNotFoundError
```

Cada tipo de exceção indica uma categoria específica de problema. Conhecer os tipos mais comuns ajuda a escrever tratamentos mais precisos.

## Try, except, else e finally

A estrutura completa de tratamento de exceções em Python tem quatro blocos:

```python
def dividir(a, b):
    """Demonstra a estrutura completa de tratamento de exceções."""
    try:
        resultado = a / b
    except ZeroDivisionError:
        print("Erro: divisão por zero não é permitida.")
        return None
    except TypeError as e:
        print(f"Erro de tipo: {e}")
        return None
    else:
        # Executado apenas se NÃO houve exceção
        print(f"Divisão realizada com sucesso: {a} / {b}")
        return resultado
    finally:
        # Executado SEMPRE, com ou sem exceção
        print("Operação de divisão finalizada.")

# Testando
print(dividir(10, 3))    # Sucesso
print(dividir(10, 0))    # ZeroDivisionError
print(dividir("10", 3))  # TypeError
```

O bloco `else` é frequentemente subutilizado, mas é valioso: ele deixa claro que determinado código só deve executar quando não houve erro. O bloco `finally` é ideal para liberar recursos como conexões de banco de dados e arquivos abertos.

## Capturando múltiplas exceções

Existem diferentes formas de capturar mais de um tipo de exceção:

```python
def processar_dado(valor):
    """Processa um dado com múltiplos tratamentos."""
    try:
        numero = int(valor)
        resultado = 100 / numero
        return resultado
    except (ValueError, TypeError) as e:
        # Captura múltiplas exceções no mesmo bloco
        print(f"Erro na conversão: {e}")
        return None
    except ZeroDivisionError:
        print("O valor não pode ser zero.")
        return None

# Testando
print(processar_dado("5"))     # 20.0
print(processar_dado("abc"))   # Erro na conversão
print(processar_dado("0"))     # Não pode ser zero
print(processar_dado(None))    # Erro na conversão
```

Evite capturar `Exception` genericamente sem necessidade. Tratar exceções específicas torna o código mais previsível e facilita a identificação de problemas.

## Levantando exceções

Às vezes, é seu código que precisa sinalizar um erro. Use `raise` para levantar exceções:

```python
def validar_idade(idade):
    """Valida se a idade está dentro dos limites aceitáveis."""
    if not isinstance(idade, int):
        raise TypeError(f"Idade deve ser um inteiro, recebeu {type(idade).__name__}")
    if idade < 0:
        raise ValueError("Idade não pode ser negativa.")
    if idade > 150:
        raise ValueError("Idade não pode ser maior que 150.")
    return True

def cadastrar_usuario(nome, idade):
    """Cadastra um usuário com validação."""
    try:
        validar_idade(idade)
        print(f"Usuário '{nome}' cadastrado com idade {idade}.")
    except (TypeError, ValueError) as e:
        print(f"Erro no cadastro: {e}")

cadastrar_usuario("Ana", 25)        # Sucesso
cadastrar_usuario("Bruno", -5)      # Erro: negativa
cadastrar_usuario("Carla", "vinte") # Erro: tipo
```

## Exceções personalizadas

Para projetos maiores, criar suas próprias exceções melhora significativamente a clareza do código:

```python
class ErroAplicacao(Exception):
    """Exceção base para erros da aplicação."""
    pass

class ErroValidacao(ErroAplicacao):
    """Erro de validação de dados."""
    def __init__(self, campo, mensagem):
        self.campo = campo
        self.mensagem = mensagem
        super().__init__(f"Validação falhou no campo '{campo}': {mensagem}")

class ErroAutenticacao(ErroAplicacao):
    """Erro de autenticação do usuário."""
    def __init__(self, mensagem="Credenciais inválidas"):
        self.mensagem = mensagem
        super().__init__(mensagem)

class ErroPermissao(ErroAplicacao):
    """Erro de permissão insuficiente."""
    def __init__(self, recurso, acao):
        self.recurso = recurso
        self.acao = acao
        super().__init__(f"Sem permissão para {acao} o recurso '{recurso}'")

# Usando exceções personalizadas
def validar_email(email):
    if not email or "@" not in email:
        raise ErroValidacao("email", "Formato de e-mail inválido")
    return True

def autenticar(usuario, senha):
    usuarios_validos = {"admin": "senha123"}
    if usuario not in usuarios_validos or usuarios_validos[usuario] != senha:
        raise ErroAutenticacao()
    return True

try:
    validar_email("usuario_sem_arroba")
except ErroValidacao as e:
    print(f"Campo: {e.campo}")
    print(f"Mensagem: {e.mensagem}")

try:
    autenticar("admin", "senha_errada")
except ErroAutenticacao as e:
    print(f"Falha na autenticação: {e.mensagem}")
```

Criar uma hierarquia de exceções permite capturar erros em diferentes níveis de granularidade. Capturar `ErroAplicacao` pega todos os erros da sua aplicação, enquanto `ErroValidacao` captura apenas erros de validação.

## Padrão de contexto seguro

O gerenciador de contexto (`with`) é a maneira mais segura de lidar com recursos que precisam ser liberados:

```python
class ConexaoBanco:
    """Simula uma conexão com banco de dados."""

    def __init__(self, nome_banco):
        self.nome_banco = nome_banco
        self.conectado = False

    def __enter__(self):
        self.conectado = True
        print(f"Conectado ao banco '{self.nome_banco}'")
        return self

    def __exit__(self, tipo_exc, valor_exc, traceback):
        self.conectado = False
        print(f"Desconectado do banco '{self.nome_banco}'")
        if tipo_exc is not None:
            print(f"Erro durante operação: {valor_exc}")
        return False  # Não suprime a exceção

    def executar(self, query):
        if not self.conectado:
            raise RuntimeError("Não conectado ao banco.")
        print(f"Executando: {query}")

# Uso seguro com with
with ConexaoBanco("meu_banco") as db:
    db.executar("SELECT * FROM usuarios")
    db.executar("UPDATE config SET valor = 'novo'")
# A conexão é fechada automaticamente, mesmo se houver erro
```

## Logging de exceções

Em produção, imprimir erros no console não é suficiente. Use o módulo `logging` para registrar exceções de forma adequada:

```python
import logging

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)

def processar_pedido(pedido_id):
    """Processa um pedido com logging adequado."""
    logger.info(f"Iniciando processamento do pedido {pedido_id}")
    try:
        # Simulação de processamento
        if pedido_id <= 0:
            raise ValueError("ID do pedido deve ser positivo")
        logger.info(f"Pedido {pedido_id} processado com sucesso")
        return True
    except ValueError as e:
        logger.warning(f"Dado inválido no pedido {pedido_id}: {e}")
        return False
    except Exception as e:
        logger.exception(f"Erro inesperado ao processar pedido {pedido_id}")
        return False

processar_pedido(42)
processar_pedido(-1)
```

O método `logger.exception()` registra automaticamente o traceback completo, o que é essencial para depuração.

## Boas práticas no tratamento de erros

Para escrever código robusto e profissional:

- **Seja específico**: capture exceções específicas, não `Exception` genérico.
- **Não silencie erros**: evite blocos `except` vazios com `pass`. Se capturou, faça algo com o erro.
- **Use else e finally**: o bloco `else` mantém o try enxuto, e o `finally` garante limpeza de recursos.
- **Crie exceções personalizadas**: para projetos médios e grandes, exceções customizadas melhoram a clareza.
- **Documente exceções**: nas docstrings das funções, liste as exceções que podem ser levantadas.
- **Registre erros**: use `logging` em vez de `print` para produção.
- **Falhe cedo**: valide dados na entrada, não no meio do processamento.

## Conclusão

O tratamento de erros é uma habilidade fundamental que separa código amador de código profissional. Python oferece ferramentas poderosas para lidar com exceções de forma elegante e eficiente. Dominar try/except, criar exceções personalizadas e seguir boas práticas de logging garantem que suas aplicações sejam robustas e fáceis de manter.

Como próximos passos, estude o módulo `logging` em profundidade, explore decoradores para tratamento de erros reutilizável e aprenda sobre validação de dados com bibliotecas como Pydantic, que automatizam grande parte da validação em projetos modernos.

> **Tratamento de erros em outras linguagens**: <a href="https://rustlang.com.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'rustlang.com.br' })">Rust</a> adota uma abordagem radicalmente diferente com os tipos `Result<T, E>` e `Option<T>`, eliminando exceções em tempo de execução e forcando o tratamento de erros em tempo de compilação. <a href="https://golang.com.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'golang.com.br' })">Go</a> tambem evita exceções, preferindo retorno explicito de erros com o pattern `valor, err := funcao()`, o que torna o fluxo de erros sempre visivel no codigo.
