Context manager
1. Utiliser un context manager
Un context manager permet de grouper des instructions, et d’exécuter automatiquement du code au préalable et a posteriori.
with open('data', 'w') as mon_fichier: (1)
for i in range(-10,10):
print(i, file=mon_fichier)
(2)
1 | ici, le fichier est ouvert |
2 | en sortie de bloc, le fichier est automatiquement fermé |
Ce code est à peu près équivalent à :
mon_fichier = open("data", "w")
for i in range(-10,10):
print(i, file=mon_fichier)
mon_fichier.close()
Globalement, l’intérêt du context manager est de doter le traitement à réaliser d’un préambule et d’une conclusion, comme :
-
une ouverture / fermeture (fichiers, sockets, etc.)
-
un verrouillage / déverrouillage (fichiers, transactions, code, etc.)
-
une allocation / libération (mémoire, session, etc.)
-
une connexion / déconnexion (réseau, sgbd, etc.)
-
un démarrage / arrêt (service, etc.)
et d’assurer que la conclusion sera réalisée, quels que soient les évènements qui peuvent advenir.
2. Ecrire un context manager
Un contexte manager Cm
est une classe possédant 2 méthodes particulières :
__enter__()
et __exit()__
,
correspondant au préambule et à la conclusion,
et qui, de ce fait, s’utilise comme :
with Cm() : (1)
(2)
...
(3)
1 | création d’un context_manager anonyme |
2 | exécution de Cm() .__enter__()` |
3 | exécution de Cm() .__exit__(…)` |
ou
with Cm() as mon_context_manager: (1)
(2)
...
(3)
1 | création d’une instance mon_context_manager de type context_manager |
2 | exécution de mon_context_manager.__enter__() |
3 | exécution de mon_context_manager.__exit__(…) |
2.1. Méthodes __enter__()
et __exit__()
__enter__(self)
-
Cette méthode implémente le préambule, et doit renvoyer ce que l’on veut récupérer dans la variable spécifiée après
as
. __exit__(self,type,value,traceback)
-
Cette méthode implémente l’épilogue. Elle est définie avec 4 paramètres.
2.2. Arguments
Des arguments peuvent être spécifiés à la création du context manager :
with Cm(arg1,arg2) as mon_context_manager:
...
Ils sont alors récupérables via les paramètres du constructeur.
2.3. __exit__()
Cette méthode est déclarée comme __exit__(self,type,value,traceback)
.
Si l’on entre dans __exit__()
en situation normale
(c’est-à-dire parce que l’exécution du bloc se termine normalement),
alors les paramètres n’ont pas d’intérêt (ils valent None
).
Si l’on entre dans __exit__()
parce qu’une exception a été lancée depuis le bloc
(donc son exécution s’est terminée prématurément),
alors on récupère dans les paramètres le type de l’exception (type
), sa valeur (value
) et un objet permettant d’accéder à la pile des appels en cours (traceback
).
En sortant de __exit__()
, si celle-ci renvoie True
, alors l’exception est attrapée et supposée traitée
(et par conséquent l’exécution du programme se poursuit normalement, après le context manager).
Sinon (cas où __exit__()
ne renvoie pas True
) l’exception poursuit sa remontée.