EAFP vs LBYL
Python favorece EAFP (Easier to Ask Forgiveness than Permission - Mais fácil pedir perdão do que permissão): tente a operação e trate a falha com exceções. LBYL (Look Before You Leap - Olhe antes de pular) verifica as condições primeiro. Ambos são válidos; EAFP é idiomático quando o caminho feliz é comum e as falhas são excepcionais.
Receita
Cartão de receita de referência rápida - pronto para copiar e colar.
# EAFP - tente, depois trate
try:
value = mapping[key]
except KeyError:
value = default
# LBYL - guarde, depois aja
if key in mapping:
value = mapping[key]
else:
value = defaultQuando usar isso:
- EAFP quando o caminho de sucesso domina e uma busca falha é rara
- LBYL quando a falha é esperada e você quer evitar o overhead de exceções
- EAFP quando verificar todas as pré-condições é mais difícil do que tentar (duck typing)
- LBYL em loops apertados onde exceções disparariam milhares de vezes por segundo
- EAFP quando múltiplos modos de falha colapsam em um único bloco
except
Exemplo de Trabalho
Um parser aceita entradas de dict ou objeto usando duck typing EAFP, com LBYL apenas para ramificação de tipo barata.
from typing import Any
def get_name(record: Any, default: str = "unknown") -> str:
"""Extrai um nome de um registro semelhante a dict ou baseado em atributo."""
if isinstance(record, dict):
return record.get("name", default)
try:
return record.name
except AttributeError:
return default
def parse_user_id(raw: str) -> int:
try:
return int(raw)
except ValueError as exc:
raise ValueError(f"id de usuário inválido: {raw!r}") from exc
samples = [
{"name": "Ada"},
type("User", (), {"name": "Grace"})(),
object(),
]
for sample in samples:
print(get_name(sample))
print(parse_user_id("42"))O que isso demonstra:
- O caminho do Dict usa
.get()(guarda estilo LBYL via API) - sem exceção para chaves ausentes - O acesso ao atributo usa EAFP - um
trycobre muitas formas de objeto - Re-lançar com
from excpreserva a cadeia de traceback original - Duck typing evita cadeias
hasattrque correm com atributos dinâmicos
Mergulho Profundo
Como Funciona
- EAFP executa a operação; Python levanta uma exceção específica em caso de falha
- LBYL avalia predicados (
in,isinstance,hasattr) antes da operação - O tratamento de exceções tem um pequeno custo de configuração; em loops quentes, milhões de exceções prejudicam
try/exceptem torno do caminho de sucesso mantém o código linear e legível- Múltiplas cláusulas de guarda (LBYL) frequentemente duplicam o trabalho que a operação faria de qualquer maneira
EAFP vs LBYL em Resumo
| Estilo | Força | Fraqueza |
|---|---|---|
| EAFP | Caminho feliz linear, lida com corridas | Custo de exceção se a falha for comum |
| LBYL | Previsível quando a falha é frequente | Guardas verbosas, corridas TOCTOU com estado mutável |
Notas de Python
# Prefira EAFP para existência de arquivo quando você o abrirá imediatamente de qualquer maneira
try:
with open(path) as f:
data = f.read()
except FileNotFoundError:
data = ""
# Prefira LBYL quando a falha é a norma (verificando chaves opcionais)
for key in optional_keys:
if key in cache:
process(cache[key])Armadilhas
- TOCTOU com LBYL - verificar
key in dicte depoisdict[key]pode falhar se outro thread excluir a chave. Correção: use EAFP (try/except KeyError) ou.get(). except:vazio - EAFP tenta capturar tudo. Correção: capture exceções específicas (KeyError,ValueError,AttributeError).- Duplicação
hasattr+getattr-if hasattr(x, "foo"): x.foochamagetattrduas vezes. Correção: use EAFP comtry/except AttributeError. - Fluxo de controle impulsionado por exceções em loops - analisar cada linha com
int()em um loop apertado é lento quando a maioria das linhas falha. Correção: pré-filtre com regex ou validação LBYL. - Engolir exceções -
except: passvazio esconde bugs. Correção: registre, relance ou retorne um sentinela com tipagem explícita.
Alternativas
| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
.get() / setdefault() | Padrões de chave ausente de Dict | Você precisa distinguir entre valor ausente e None |
Guardas isinstance | Ramificação de tipo é a decisão real | Você só precisa de comportamento duck-typed |
match / correspondência de padrões estruturais | Formas de tipo complexas (3.10+) | Busca simples de chave |
| Tipos opcionais + verificações estáticas | Contratos de API são fixos no tempo de compilação | Duck typing em tempo de execução é necessário |
FAQs
O que significa EAFP?
"Easier to Ask Forgiveness than Permission" (Mais fácil pedir perdão do que permissão) - tente a operação e trate exceções em vez de verificar todas as pré-condições primeiro.
EAFP é sempre mais Pythonic?
Não. Use EAFP quando o sucesso é comum e as exceções são raras. Use LBYL quando a falha é esperada ou as exceções dominariam o desempenho.
Quando devo usar dict.get() em vez de try/except?
Quando o contêiner é um dict e uma chave ausente é um resultado normal. .get() é LBYL embutido na API - sem custo de exceção.
EAFP funciona com código async?
Sim. try/except funciona em torno de await da mesma forma que o código síncrono. Não use exceções para controle de fluxo em loops async apertados também.
Como preservo tracebacks ao relançar?
Use raise NewError("msg") from exc para encadear exceções, ou raise vazio dentro de except para relançar o original.
hasattr é seguro antes de getattr?
Entre hasattr e o acesso, outra corrotina pode excluir o atributo. Prefira EAFP ou getattr(obj, "name", default).
E sobre verificações de permissão antes do acesso a arquivos?
Para caminhos sensíveis à segurança, verificações explícitas podem ser necessárias por política. Para I/O comum, EAFP com FileNotFoundError é aceitável.
EAFP pode substituir todos os if-statements?
Não. Ramificações de lógica de negócios (if user.is_admin) não são casos de exceção. Reserve EAFP para falhas operacionais.
Como isso se relaciona com duck typing?
EAFP abraça o duck typing: chame o método que você precisa; trate AttributeError se o objeto não o suportar.
Devo capturar Exception ou BaseException?
Capture tipos específicos primeiro. Nunca capture BaseException (inclui KeyboardInterrupt, SystemExit) em código de aplicação.
Relacionados
- Context Managers as a Pattern - EAFP para limpeza de recursos
- Null Object & Sentinels - evite valores ausentes ambíguos
- Pythonic Patterns Basics - visão geral da seção
- Common Anti-Patterns - quando guardas dão errado
Versões do Stack: Esta página foi escrita para Python 3.14.0 (estável 3.14, manutenção 3.13), FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, e uv 0.6+.