---
title: "Try/Except em Python: O que É e Como Funciona | Python Brasil"
url: "https://python.dev.br/glossario/try-except/"
markdown_url: "https://python.dev.br/glossario/try-except.MD"
description: "Try/except em Python: EAFP vs LBYL, múltiplos excepts, contextlib.suppress, traceback, padrões de retry com tenacity e quando não usar try/except."
date: "2026-01-05"
author: ""
---

# Try/Except em Python: O que É e Como Funciona | Python Brasil

Try/except em Python: EAFP vs LBYL, múltiplos excepts, contextlib.suppress, traceback, padrões de retry com tenacity e quando não usar try/except.


## O que é Try/Except?

O bloco **try/except** é a estrutura do Python para **tratamento de erros em tempo de execução**. Ele permite "tentar" executar um bloco de código e, caso uma exceção seja lançada, capturá-la e lidar com ela de forma controlada, sem que o programa quebre inesperadamente.

Mais do que uma sintaxe de tratamento de erros, o `try/except` representa uma **filosofia de programação** característica do Python: preferir tentar fazer e lidar com falhas do que verificar condições antecipadamente.

## Sintaxe completa

```python
try:
    # Código que pode lançar uma exceção
    resultado = int(input("Digite um número: "))
    valor = 100 / resultado

except ZeroDivisionError:
    # Executado especificamente para divisão por zero
    print("Não é possível dividir por zero.")

except ValueError as e:
    # Captura a exceção e a expõe como 'e'
    print(f"Entrada inválida: {e}")

except (TypeError, AttributeError) as e:
    # Captura múltiplos tipos na mesma cláusula
    print(f"Erro de tipo ou atributo: {e}")

except Exception as e:
    # Captura qualquer exceção que herde de Exception
    # Use com parcimônia: prefira ser específico
    print(f"Erro inesperado: {e}")
    raise  # Re-lança para não silenciar erros desconhecidos

else:
    # Executado APENAS se nenhuma exceção foi lançada no bloco try
    print(f"Resultado: {valor}")

finally:
    # Executado SEMPRE: com sucesso, com erro, ou mesmo com return/break
    print("Bloco finally sempre executado.")
```

## EAFP vs LBYL: a filosofia Python

O Python tem duas abordagens para lidar com situações que podem dar errado:

**LBYL — Look Before You Leap** (Olhe antes de pular): verificar condições antes de executar a operação. Estilo comum em C, Java e outras linguagens.

**EAFP — Easier to Ask Forgiveness than Permission** (Mais fácil pedir perdão que permissão): tentar executar e tratar o erro se ocorrer. Este é o **estilo pythônico**.

```python
# LBYL: verificação antecipada
def obter_idade_lbyl(dados: dict, chave: str) -> int | None:
    if isinstance(dados, dict) and chave in dados:
        valor = dados[chave]
        if isinstance(valor, int) and valor > 0:
            return valor
    return None

# EAFP: tentativa e tratamento
def obter_idade_eafp(dados: dict, chave: str) -> int | None:
    try:
        valor = dados[chave]
        assert isinstance(valor, int) and valor > 0
        return valor
    except (KeyError, AssertionError, TypeError):
        return None

# LBYL tem um problema sutil: condição de corrida
# Em código concorrente, o estado pode mudar entre a verificação e o uso
import os

# LBYL (problemático em concorrência):
if os.path.exists("arquivo.txt"):
    # Outro processo pode deletar o arquivo aqui!
    with open("arquivo.txt") as f:
        conteudo = f.read()

# EAFP (seguro):
try:
    with open("arquivo.txt") as f:
        conteudo = f.read()
except FileNotFoundError:
    conteudo = ""
```

## Ordenando múltiplas cláusulas except

A ordem das cláusulas `except` importa: o Python verifica cada uma de cima para baixo e executa a primeira que corresponder. Coloque exceções **mais específicas antes das mais gerais**:

```python
# ERRADO: LookupError captura KeyError e IndexError antes delas
try:
    valor = dicionario[chave]
except LookupError:  # Captura KeyError e IndexError
    print("Não encontrado")
except KeyError:     # NUNCA será alcançado
    print("Chave inexistente")

# CORRETO: específico primeiro, geral depois
try:
    valor = dicionario[chave]
except KeyError:
    print(f"Chave '{chave}' não existe no dicionário")
except LookupError:
    print("Erro de busca genérico")
except Exception:
    print("Erro inesperado")
    raise
```

## Performance: o custo do try/except

```python
import timeit

# O bloco try tem custo MÍNIMO quando bem-sucedido
# A penalidade real é na CRIAÇÃO E PROPAGAÇÃO da exceção

# Medir custo do try sem exceção vs verificação prévia
codigo_try = """
try:
    x = d['chave']
except KeyError:
    x = None
"""

codigo_get = """
x = d.get('chave')
"""

d = {'chave': 42}

t1 = timeit.timeit(codigo_try, setup="d = {'chave': 42}", number=1_000_000)
t2 = timeit.timeit(codigo_get, setup="d = {'chave': 42}", number=1_000_000)
print(f"try/except (sucesso): {t1:.3f}s")
print(f"dict.get:             {t2:.3f}s")
# Ambos são muito próximos quando não há exceção

# Com exceção lançada, o custo aumenta significativamente
# Use LBYL em loops muito apertados com alta taxa de falha esperada
```

## Context managers como alternativa

Muitas situações que exigiam `try/finally` manual podem ser expressas com gerenciadores de contexto, que são mais claros e menos propensos a erros:

```python
# Sem context manager (verboso e propenso a erros)
arquivo = open("dados.txt")
try:
    conteudo = arquivo.read()
finally:
    arquivo.close()  # E se esquecermos? Vazamento de recurso.

# Com context manager (limpo e seguro)
with open("dados.txt") as arquivo:
    conteudo = arquivo.read()
# arquivo.close() é chamado automaticamente

# Context managers para locks, transações, conexões...
import threading

lock = threading.Lock()
with lock:  # Garantia de liberação mesmo se exceção for lançada
    recurso_compartilhado.modificar()

# Criando seu próprio context manager
from contextlib import contextmanager

@contextmanager
def transacao_banco(conexao):
    try:
        yield conexao
        conexao.commit()
    except Exception:
        conexao.rollback()
        raise
```

## contextlib.suppress: silenciando exceções específicas

```python
from contextlib import suppress
import os

# Sem suppress (verboso)
try:
    os.remove("arquivo_temporario.txt")
except FileNotFoundError:
    pass  # Tudo bem se não existir

# Com suppress (mais expressivo)
with suppress(FileNotFoundError):
    os.remove("arquivo_temporario.txt")

# Múltiplas exceções
with suppress(FileNotFoundError, PermissionError):
    os.remove("arquivo_protegido.txt")
```

## Módulo traceback e sys.exc_info()

```python
import traceback
import sys

def analisar_excecao():
    try:
        1 / 0
    except ZeroDivisionError:
        # sys.exc_info(): retorna (tipo, valor, traceback)
        tipo, valor, tb = sys.exc_info()
        print(f"Tipo: {tipo.__name__}")
        print(f"Valor: {valor}")

        # traceback.format_exc(): traceback como string
        texto_tb = traceback.format_exc()
        print(texto_tb)

        # traceback.print_exc(): imprime o traceback completo
        traceback.print_exc()

        # Extraindo informações específicas
        frames = traceback.extract_tb(tb)
        ultimo_frame = frames[-1]
        print(f"Arquivo: {ultimo_frame.filename}")
        print(f"Linha: {ultimo_frame.lineno}")
        print(f"Função: {ultimo_frame.name}")
        print(f"Código: {ultimo_frame.line}")
```

## logging.exception: registrando erros com contexto

```python
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def processar_pagamento(pedido_id: int, valor: float) -> bool:
    try:
        gateway = GatewayPagamento()
        resultado = gateway.cobrar(pedido_id, valor)
        logger.info("Pagamento aprovado: pedido=%d, valor=%.2f", pedido_id, valor)
        return True
    except GatewayTimeout:
        # logging.exception inclui o traceback completo
        logger.exception(
            "Timeout no gateway de pagamento: pedido=%d, valor=%.2f",
            pedido_id, valor
        )
        return False
    except PagamentoRecusado as e:
        logger.warning(
            "Pagamento recusado: pedido=%d, codigo=%s, motivo=%s",
            pedido_id, e.codigo, e.motivo
        )
        return False
    except Exception:
        logger.exception("Erro inesperado no processamento do pagamento")
        raise  # Re-lança exceções verdadeiramente inesperadas
```

## Padrões de retry com tenacity

Tentar novamente após falhas transientes é um padrão comum em sistemas distribuídos:

```python
# pip install tenacity
from tenacity import (
    retry,
    stop_after_attempt,
    wait_exponential,
    retry_if_exception_type,
    before_sleep_log
)
import logging
import requests

logger = logging.getLogger(__name__)

@retry(
    retry=retry_if_exception_type((ConnectionError, TimeoutError)),
    stop=stop_after_attempt(3),
    wait=wait_exponential(multiplier=1, min=1, max=10),
    before_sleep=before_sleep_log(logger, logging.WARNING)
)
def buscar_dados_api(url: str) -> dict:
    """Busca dados com retry automático em falhas de rede."""
    resposta = requests.get(url, timeout=5)
    resposta.raise_for_status()
    return resposta.json()

# Implementação manual simples (sem biblioteca)
import time

def com_retry(funcao, tentativas=3, espera=1.0, excecoes=(Exception,)):
    for tentativa in range(1, tentativas + 1):
        try:
            return funcao()
        except excecoes as e:
            if tentativa == tentativas:
                raise
            logger.warning("Tentativa %d/%d falhou: %s", tentativa, tentativas, e)
            time.sleep(espera * tentativa)  # Backoff linear
```

## Quando NÃO usar try/except

Existem situações em que `try/except` não é a ferramenta adequada:

**Não use para controle de fluxo normal**: se uma condição é esperada e rotineira, use lógica condicional. `dict.get()`, `list.index()` com verificação prévia, ou operadores como `or` são mais claros.

**Não silencie exceções sem motivo**: `except: pass` esconde bugs. Sempre logue ou trate a exceção de forma significativa.

**Não capture exceções mais amplas do que o necessário**: `except Exception` em vez de `except (ValueError, KeyError)` dificulta a depuração.

**Não use para validação de entrada do usuário em loops**: valide antes com condicionais; o overhead de exceções em loops muito apertados é relevante.

```python
# RUIM: usar exceção para lógica de negócio rotineira
def verificar_usuario_existe(user_id: int) -> bool:
    try:
        buscar_usuario(user_id)
        return True
    except UsuarioNaoEncontrado:
        return False

# BOM: a função de busca pode retornar None
def verificar_usuario_existe(user_id: int) -> bool:
    return buscar_usuario(user_id) is not None
```

## Termos Relacionados

- [Exceções](/glossario/exception/) - Tipos de exceções em Python
- [Context Manager](/glossario/context-manager/) - Outra forma de gerenciar recursos
- [Python](/glossario/python/) - A linguagem de programação
