Question 1Quand tu décores une fonction génératrice avec @contextmanager, pourquoi doit-elle yielder exactement une fois ?
contextlib — Gestion de ressources et with personnalisé
Écrire son propre with sans classe grâce à @contextmanager et yield, garantir le nettoyage avec try/finally, et absorber des exceptions ciblées avec suppress.
contextlib est le module à utiliser quand tu veux écrire ton propre with. On va parcourir ses deux outils les plus simples dans l'ordre : @contextmanager pour la façon la plus simple d'en définir un, et suppress pour absorber des exceptions spécifiques.
@contextmanager — définir un with facilement
L'instruction with de Python est la façon sûre de gérer "les choses qu'il faut nettoyer après usage" — open de fichier, connexions BD, acquisition de verrou, etc. Pour faire fonctionner une classe avec with à la main, tu dois définir __enter__ / __exit__, ce qui fait beaucoup de code répétitif. @contextmanager est un raccourci : écris un seul générateur (une fonction qui contient yield) et tu obtiens un gestionnaire de contexte qui marche avec with. Le code avant yield est "le début de l'action", et le code après est "le nettoyage".
yield est ce qui est lié par as dans l'instruction with.from contextlib import contextmanager
# --- Référence : construire une classe compatible with ----------
# class Section:
# def __init__(self, name):
# self.name = name
# def __enter__(self):
# print(f"--- {self.name} début ---")
# return self # valeur liée par le `as` de with
# def __exit__(self, exc_type, exc, tb):
# print(f"--- {self.name} fin ---")
# ----------------------------------------------------------
# Version @contextmanager : une fonction génératrice fait le même travail
@contextmanager
def section(name):
print(f"--- {name} début ---")
yield # le corps de with s'exécute ici
print(f"--- {name} fin ---")
# Utilisation
with section("agrégation"):
total = sum(range(100))
print("Total :", total)
# Sortie :
# --- agrégation début ---
# Total : 4950
# --- agrégation fin ---
yield directement à setup/teardown — bien moins de code.Utilise try/finally pour garantir le nettoyage même sur exception
Le code après yield peut ne pas s'exécuter si une exception est levée à l'intérieur du bloc with. Pour un nettoyage qui doit toujours arriver — fermer des fichiers, libérer des verrous — enveloppe le corps du générateur dans try : yield finally : cleanup() pour la sécurité.
suppress — absorber des exceptions spécifiques
contextlib.suppress(ExceptionType, ...) est un gestionnaire de contexte pour absorber les exceptions spécifiées et continuer l'exécution. Le motif "ignore juste cette exception et passe à la suite" — équivalent à try : ... except KeyError : pass — tient en une seule ligne. Tu peux lister plusieurs types d'exceptions à la fois, et tout ce qui est en dehors de la liste se propage normalement.
from contextlib import suppress
import os
# "Exécute avec les valeurs par défaut même si le fichier n'existe pas"
config = {"theme": "light", "font_size": 14}
with suppress(FileNotFoundError):
with open("user_config.txt") as f:
config["theme"] = f.read().strip()
# Ne plante pas si user_config.txt manque — config garde ses valeurs par défaut
print(config)
# → {'theme': 'light', 'font_size': 14}
# "Saute silencieusement si déjà supprimé"
with suppress(FileNotFoundError):
os.remove("old.tmp")
print("Suppression terminée (OK s'il n'existait pas)")
Vérification des connaissances
Répondez à chaque question une par une.
Question 2À l'intérieur de with suppress(KeyError):, que se passe-t-il quand KeyError est levée ?