Noções Básicas de Padrões Pythonic
10 exemplos para você começar com Padrões Pythonic - 7 básicos e 3 intermediários.
Pré-requisitos
- Python 3.14.0 instalado.
- Leia
import thispara o Zen do Python - legibilidade conta.
Exemplos Básicos
1. Consulta de Chave EAFP
Tente a operação; trate KeyError para chaves ausentes.
def get_score(scores: dict[str, int], player: str) -> int:
try:
return scores[player]
except KeyError:
return 0- EAFP mantém o caminho feliz sem indentação.
- Use
.get()quando um padrão de dicionário for suficiente. - Não capture exceções excessivamente amplas em torno de consultas simples.
Relacionado: EAFP vs LBYL - quando se proteger em vez disso
2. Gerenciador de Contexto para Arquivos
Garanta a limpeza com with.
from pathlib import Path
path = Path("notes.txt")
path.write_text("hello", encoding="utf-8")
with path.open(encoding="utf-8") as f:
print(f.read())- Arquivos fecham mesmo quando a leitura gera erro.
- Prefira
pathlibem vez de strings de caminho manuais. - Especifique
encodingpara arquivos de texto em todas as plataformas.
Relacionado: Gerenciadores de Contexto como Padrão - gerenciadores personalizados
3. Dicionário de Estratégia
Substitua if/elif por um registro de chamáveis.
FORMATTERS = {
"json": lambda data: str(data),
"upper": lambda data: str(data).upper(),
}
def format_value(kind: str, data) -> str:
return FORMATTERS[kind](data)- Novos formatos adicionam uma entrada de dicionário, não outro ramo.
- Valide chaves e gere erros claros para tipos desconhecidos.
- Nomeie funções quando a lógica exceder lambdas.
Relacionado: Padrões de Estratégia e Despacho - singledispatch também
4. Função Fábrica
Oculte a escolha da classe concreta atrás de uma função construtora.
from dataclasses import dataclass
@dataclass
class ConsoleLogger:
def info(self, msg: str) -> None:
print(msg)
def logger_from_env(debug: bool) -> ConsoleLogger:
return ConsoleLogger()- Chamadores dependem da fábrica, não dos caminhos de importação das implementações.
- Fábricas pertencem à raiz de composição ou ao lado dos tipos de produto.
- Mantenha as fábricas livres de efeitos colaterais de rede.
Relacionado: Padrões Factory & Builder - builders para objetos complexos
5. Barramento de Eventos Simples
Desacople publicadores e assinantes com tópicos.
from collections import defaultdict
bus: dict[str, list] = defaultdict(list)
bus["user.created"].append(lambda e, p: print("audit", p))
bus["user.created"][0]("user.created", {"id": 1})- Assinantes devem ser rápidos; descarregue E/S pesada em outro lugar.
- Copie listas de manipuladores durante a emissão para evitar bugs de mutação.
- Injete um objeto de barramento em vez de usar um singleton global.
Relacionado: Observer & Pub/Sub - barramento em formato de produção
6. Injeção de Construtor
Passe dependências explicitamente para testabilidade.
class Greeter:
def __init__(self, salutation: str) -> None:
self._salutation = salutation
def greet(self, name: str) -> str:
return f"{self._salutation}, {name}!"- Dependências visíveis na assinatura do construtor.
- Testes passam implementações alternativas sem monkeypatching.
- Evite construir clientes de E/S dentro de métodos de serviço.
Relacionado: Injeção de Dependência em Python - protocolos e conexão
7. Sentinela para Valores Não Definidos
Diferencie "não passado" de None.
UNSET = object()
def connect(timeout=UNSET):
if timeout is UNSET:
timeout = 30.0
return timeout- Compare sentinelas com
is, não com==. - Documente a semântica de três estados quando
Nonefor dado válido. - Modelos Pydantic podem usar
model_fields_setem vez disso para APIs.
Relacionado: Null Object & Sentinels - objetos nulos
Exemplos Intermediários
8. Serialização singledispatch
Adicione serializadores específicos de tipo sem editar a função principal.
from functools import singledispatch
@singledispatch
def to_repr(obj) -> str:
raise TypeError(type(obj))
@to_repr.register(int)
def _(n: int) -> str:
return f"int:{n}"
print(to_repr(42))- Registre novos tipos em novos módulos para layouts de plugin.
- A função base deve gerar
TypeErrorclaro para tipos não suportados. - Prefira estratégias de dicionário para despacho com chave de string em vez disso.
Relacionado: Padrões de Estratégia e Despacho - comparação completa
9. Builder Fluente com Validação
Monte um objeto de configuração passo a passo; valide em build().
class QueryBuilder:
def __init__(self) -> None:
self._filters: list[str] = []
def where(self, clause: str) -> "QueryBuilder":
self._filters.append(clause)
return self
def build(self) -> str:
if not self._filters:
raise ValueError("need at least one filter")
return " AND ".join(self._filters)
sql = QueryBuilder().where("id > 0").where("active").build()
print(sql)- Builders servem para muitos campos opcionais e restrições de ordenação.
- Retorne
selfpara encadeamento; valide invariantes uma vez embuild(). - Dataclasses simples podem substituir builders quando os campos são poucos.
Relacionado: Padrões Factory & Builder - factory vs builder
10. Logger Null Object
Evite ramificações quando o logging estiver desativado.
class NullLogger:
def info(self, msg: str) -> None:
pass
def job(logger=NullLogger()):
logger.info("run")- Objetos nulos implementam a interface real com no-ops.
- Não use objetos nulos para ocultar dependências obrigatórias ausentes em produção.
- Prefira injeção explícita em vez de instâncias padrão mutáveis em bibliotecas.
Relacionado: Anti-Padrões Comuns - padrões padrão mutáveis e god objects
Versões da 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+.