2.24. Gestionnaires de contexte¶
L’instruction with exécute du code d’initialisation, puis un corps, puis du code de nettoyage – avec la garantie que le nettoyage s’exécute même lorsque le corps échoue en cours de route. La paire de méthodes qui fournit l’initialisation et le nettoyage s’appelle un gestionnaire de contexte.
La forme est :
with <expression> as <name>:
<body>
L’expression renvoie un gestionnaire de contexte. Python appelle sa méthode __enter__, lie éventuellement le résultat à <name>, exécute le corps, puis appelle __exit__ – que le corps se soit terminé normalement ou ait levé une exception.
__exit__ s’exécute à la fin du bloc quoi qu’il se passe à l’intérieur.¶
2.24.1. Utiliser un gestionnaire de contexte¶
L’exemple canonique est l’ouverture d’un fichier :
with open("data.txt") as f:
text = f.read()
# f is now closed, even if read() failed
open() renvoie un objet fichier qui est lui-même un gestionnaire de contexte ; __enter__ renvoie le fichier, et __exit__ le ferme. Le bloc with fait de « toujours fermer le fichier une fois terminé » le comportement par défaut plutôt qu’une chose dont l’appelant doit se souvenir.
2.24.1.1. Plusieurs gestionnaires de contexte¶
Une seule instruction with peut entrer dans plusieurs gestionnaires de contexte à la fois, séparés par des virgules :
with open("input.txt") as src, open("output.txt", "w") as dst:
dst.write(src.read())
Équivalent à deux blocs with imbriqués, mais plus plat. Les gestionnaires sont entrés de gauche à droite et quittés dans l’ordre inverse ; si __enter__ du gestionnaire de droite lève une exception, le __exit__ du gestionnaire de gauche s’exécute tout de même.
2.24.2. Écrire un gestionnaire de contexte¶
Toute classe dotée de méthodes __enter__ et __exit__ fonctionne comme un gestionnaire de contexte :
class Section:
def __init__(self, label):
self.label = label
def __enter__(self):
print("---", self.label, "---")
return self
def __exit__(self, exc_type, exc_value, traceback):
print("--- end", self.label, "---")
return False
with Section("setup"):
print("doing the work")
Sortie
--- setup ---
doing the work
--- end setup ---
__exit__ reçoit trois arguments décrivant l’exception qui a mis fin au bloc, ou trois valeurs None si le bloc s’est terminé normalement. Renvoyer False (ou None) laisse toute exception se propager après le nettoyage ; renvoyer True l’absorberait.
Utilisez les gestionnaires de contexte pour toute ressource ayant un cycle de vie « ouvrir / fermer » ou « acquérir / libérer » – pas seulement les fichiers. Ce modèle maintient le nettoyage apparié à l’initialisation à l’endroit où les deux sont introduits, de sorte qu’un oubli de fermeture au milieu d’une longue fonction ne peut pas faire fuir la ressource.