Pregunta 1Cuando decoras una función generadora con @contextmanager, ¿por qué necesita hacer yield exactamente una vez?
contextlib — Gestión de recursos y with personalizado
Aprende con ejemplos a escribir tu propio with sin clases con @contextmanager y yield, asegurar la limpieza con try / finally, y silenciar excepciones concretas con suppress.
contextlib es el módulo al que recurrir cuando quieres escribir tu propia sentencia with. Recorreremos sus dos herramientas más simples en orden: @contextmanager para la forma más simple de definir una, y suppress para silenciar excepciones específicas.
@contextmanager — define una sentencia with fácilmente
La sentencia with de Python es la forma segura de gestionar "cosas que tienes que limpiar después de usarlas" — open de archivos, conexiones a BD, adquisición de bloqueos, etc. Para hacer que una clase funcione con with a mano, necesitas definir __enter__ / __exit__, que es mucho boilerplate. @contextmanager es un atajo: escribe un solo generador (una función que contiene yield) y obtienes un context manager que funciona con with. El código antes de yield es "el inicio de la acción", y el código después es "la limpieza".
yield es lo que se enlaza con as en la sentencia with.from contextlib import contextmanager
# --- Referencia: construir una clase compatible con with ----------
# class Section:
# def __init__(self, name):
# self.name = name
# def __enter__(self):
# print(f"--- {self.name} inicio ---")
# return self # valor enlazado por el `as` del with
# def __exit__(self, exc_type, exc, tb):
# print(f"--- {self.name} fin ---")
# ----------------------------------------------------------
# Versión @contextmanager: una función generadora hace el mismo trabajo
@contextmanager
def section(name):
print(f"--- {name} inicio ---")
yield # el cuerpo del with se ejecuta aquí
print(f"--- {name} fin ---")
# Uso
with section("agregación"):
total = sum(range(100))
print("Total:", total)
# Salida:
# --- agregación inicio ---
# Total: 4950
# --- agregación fin ---
yield directamente a setup/teardown — mucho menos código.Usa try/finally para garantizar la limpieza incluso ante excepciones
El código después de yield puede no ejecutarse si se lanza una excepción dentro del bloque with. Para limpieza que siempre debe ocurrir — cerrar archivos, liberar bloqueos — envuelve el cuerpo del generador en try: yield finally: cleanup() por seguridad.
suppress — silencia excepciones específicas
contextlib.suppress(TipoExcepción, ...) es un context manager para silenciar las excepciones especificadas y continuar la ejecución. El patrón de "ignora solo esta excepción y sigue" — equivalente a try: ... except KeyError: pass — encaja en una sola línea. Puedes listar varios tipos de excepción a la vez, y cualquier cosa fuera de la lista se propaga normalmente.
from contextlib import suppress
import os
# "Ejecuta con valores por defecto incluso si el archivo no existe"
config = {"theme": "light", "font_size": 14}
with suppress(FileNotFoundError):
with open("user_config.txt") as f:
config["theme"] = f.read().strip()
# No falla si user_config.txt no existe — config conserva sus valores por defecto
print(config)
# → {'theme': 'light', 'font_size': 14}
# "Salta silenciosamente si ya fue eliminado"
with suppress(FileNotFoundError):
os.remove("old.tmp")
print("Eliminación hecha (OK si no existía)")
Verificación de conocimientos
Responde cada pregunta una a una.
Pregunta 2Dentro de with suppress(KeyError):, ¿qué pasa cuando se lanza KeyError?