Patrones Básicos de Python
10 ejemplos para empezar con Patrones de Python: 7 básicos y 3 intermedios.
Prerrequisitos
- Tener instalado Python 3.14.0.
- Leer
import thispara el Zen de Python: la legibilidad cuenta.
Ejemplos Básicos
1. Búsqueda de Clave EAFP
Intenta la operación; maneja KeyError para claves ausentes.
def get_score(scores: dict[str, int], player: str) -> int:
try:
return scores[player]
except KeyError:
return 0- EAFP mantiene la ruta feliz sin indentación.
- Usa
.get()cuando un valor predeterminado de diccionario es suficiente. - No captures excepciones demasiado amplias alrededor de búsquedas simples.
Relacionado: EAFP vs LBYL - cuándo proteger en lugar de intentar
2. Gestor de Contexto para Archivos
Garantiza la limpieza con 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())- Los archivos se cierran incluso cuando la lectura genera un error.
- Prefiere
pathlibsobre cadenas de ruta manuales. - Especifica
encodingpara archivos de texto en todas las plataformas.
Relacionado: Gestores de Contexto como Patrón - gestores personalizados
3. Diccionario de Estrategia
Reemplaza if/elif con un registro de llamables.
FORMATTERS = {
"json": lambda data: str(data),
"upper": lambda data: str(data).upper(),
}
def format_value(kind: str, data) -> str:
return FORMATTERS[kind](data)- Los nuevos formatos añaden una entrada de diccionario, no otra rama.
- Valida las claves y lanza errores claros para tipos desconocidos.
- Nombra las funciones cuando la lógica va más allá de las lambdas.
Relacionado: Patrones de Estrategia y Despacho - singledispatch también
4. Función Fábrica
Oculta la elección de la clase concreta detrás de una función constructora.
from dataclasses import dataclass
@dataclass
class ConsoleLogger:
def info(self, msg: str) -> None:
print(msg)
def logger_from_env(debug: bool) -> ConsoleLogger:
return ConsoleLogger()- Los llamadores dependen de la fábrica, no de las rutas de importación de las implementaciones.
- Las fábricas pertenecen a la raíz de composición o junto a los tipos de producto.
- Mantén las fábricas libres de efectos secundarios de red.
Relacionado: Patrones Fábrica y Constructor - constructores para objetos complejos
5. Bus de Eventos Simple
Desacopla publicadores y suscriptores con temas.
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})- Los suscriptores deben ser rápidos; descarga el I/O pesado en otro lugar.
- Copia las listas de manejadores durante la emisión para evitar errores de mutación.
- Inyecta un objeto bus en lugar de usar un singleton global.
Relacionado: Observador y Pub/Sub - bus con formato de producción
6. Inyección por Constructor
Pasa las dependencias explícitamente para la testeabilidad.
class Greeter:
def __init__(self, salutation: str) -> None:
self._salutation = salutation
def greet(self, name: str) -> str:
return f"{self._salutation}, {name}!"- Las dependencias son visibles en la firma del constructor.
- Las pruebas pasan implementaciones alternativas sin monkeypatching.
- Evita construir clientes de I/O dentro de métodos de servicio.
Relacionado: Inyección de Dependencias en Python - protocolos y cableado
7. Centinela para Valores No Establecidos
Distingue "no pasado" de None.
UNSET = object()
def connect(timeout=UNSET):
if timeout is UNSET:
timeout = 30.0
return timeout- Compara centinelas con
is, no con==. - Documenta la semántica de tres estados cuando
Nonees un dato válido. - Los modelos Pydantic pueden usar
model_fields_seten su lugar para APIs.
Relacionado: Objeto Nulo y Centinelas - objetos nulos
Ejemplos Intermedios
8. Serialización con singledispatch
Añade serializadores específicos de tipo sin editar la función 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))- Registra nuevos tipos en nuevos módulos para diseños de plugins.
- La función base debe lanzar un
TypeErrorclaro para tipos no soportados. - Prefiere estrategias de diccionario para despacho con clave de cadena en su lugar.
Relacionado: Patrones de Estrategia y Despacho - comparación completa
9. Constructor Fluido con Validación
Ensambla un objeto de configuración paso a paso; valida en 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("se necesita al menos un filtro")
return " AND ".join(self._filters)
sql = QueryBuilder().where("id > 0").where("active").build()
print(sql)- Los constructores se adaptan a muchos campos opcionales y restricciones de orden.
- Devuelve
selfpara encadenar; valida invariantes una vez enbuild(). - Las dataclasses simples pueden reemplazar a los constructores cuando los campos son pocos.
Relacionado: Patrones Fábrica y Constructor - fábrica vs constructor
10. Logger de Objeto Nulo
Omite la ramificación cuando el logging está deshabilitado.
class NullLogger:
def info(self, msg: str) -> None:
pass
def job(logger=NullLogger()):
logger.info("run")- Los objetos nulos implementan la interfaz real con no-ops.
- No uses objetos nulos para ocultar dependencias requeridas faltantes en producción.
- Prefiere la inyección explícita sobre instancias predeterminadas mutables en bibliotecas.
Relacionado: Antipatrones Comunes - valores predeterminados mutables y objetos dios
Versiones de Stack: Esta página fue escrita para Python 3.14.0 (estable 3.14, mantenimiento 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+, y uv 0.6+.