Les gestionnaires de contexte (context managers) nous permettent de gérer les ressources en spécifiant ce que nous voulons faire. Les programmeurs travaillent avec des ressources externes de temps en temps, comme des fichiers, des bases de données, etc.

gestionnaires de contexte

Avant qu’un programme accède à une ressource sur l’ordinateur, il le demande au système d’exploitation, qui lui fournit un descripteur pour cette ressource. En fait, chaque fois qu’une ressource est ouverte, nous devons nous rappeler de la fermer pour qu’elle soit libérée afin qu’un autre programme puisse l’utiliser en cas de besoin. Mais c’est plus facile à dire qu’à faire.

Pourquoi avons-nous besoin de gestionnaires de contexte ?

Les gestionnaires de contexte sont le plus souvent utilisés lorsque nous parlons de ressources. Par exemple, lire/écrire à partir de fichiers. Examinez cet extrait de code :

f = open('log.txt', 'w')
f.write('hello world')
f.close()

Tout ce que ce code fait, c’est ouvrir le fichier log.txt pour l’écriture et y écrire « hello world’. Mais supposons que le code de la ligne 2 lève une exception sans aucune raison. Dans ce cas, le fichier restera toujours ouvert, car l’interpréteur n’arrivera jamais à la ligne 3.

Ce n’est pas un problème avec un petit script de test, mais peut devenir un casse-tête si vous devez développer quelque chose de sérieux avec Python.

La gestion des erreurs ou des exceptions avec l’instruction try/finally peut régler le problème, car finally sera exécuté même si une exception est levée. Cependant, cela n’a pas l’air très pythonic !

f = open('log.txt', 'w')
try:
    f.write('hello world')
finally:
    f.close()

C’est là que l’instruction with vient nous aider. Son objectif est de rendre la gestion des ressources lisible. Cet extrait de code est fonctionnellement égal à l’exemple ci-dessus :

with open('log.txt', 'w') as f:
    f.write('hello world')

Notez que nous n’avons pas eu besoin de fermer explicitement le fichier, le gestionnaire de contexte s’en est occupé pour nous.
De plus, nous avons un code beaucoup plus propre.

Comment fonctionnent les gestionnaires de contexte ?

La logique derrière les gestionnaires de contexte est en fait assez simple. Explorons-le en écrivant notre propre gestionnaire de contexte. Pour qu’un objet soit reconnu comme gestionnaire de contexte, il doit implémenter 2 méthodes __enter__ et __exit__.

class TestContextManager:
    def __enter__(self):
        print ( 'Entrer dans le gestionnaire de contexte!' )

    def __exit__(self, *args):
        print ( 'Quitter le gestionnaire de contexte!' )

with TestContextManager():
    print ( "À l'intérieur du gestionnaire de contexte!" )

L’exécution du code.

Entrer dans le gestionnaire de contexte!
À l'intérieur du gestionnaire de contexte!
Quitter le gestionnaire de contexte!
  • La méthode __enter__ nous dit quoi faire lorsque nous acquérons la ressource, c’est-à-dire en nous donnant un objet fichier.
  • La méthode __exit__ définit ce qu’il faut faire lorsque nous quittons le gestionnaire de contexte, c’est-à-dire que nous fermons le fichier.

Essayons maintenant de lancer une exception à l’intérieur with:

with TestContextManager():
    raise Exception()

Si vous exécutez ce code, la méthode __exit__ sera appelée, un peu comme le bloc finally et try. Cela peut être utilisé pour nettoyer et libérer toutes les ressources utilisées par ce gestionnaire de contexte.

Le module contextlib

Le module contextlib fait partie de la bibliothèque standard et fournit quelques constructions communes pour vous faciliter la vie.

L’ajout le plus notable est le décorateur @contextmanager. Il vous permet de convertir n’importe quelle fonction de générateur en un gestionnaire de contexte sans code supplémentaire.

from contextlib import contextmanager

@contextmanager
def get_log_file():
    f = open('log.txt', 'w')
    try:
        yield f
    finally:
        f.close()

with get_log_file() as f:
    f.write('hello world')

Nous importons simplement contextmanager de contextlib qui sera le décorateur de notre fonction get_log_file().
Cela nous permet d’appeler get_log_file() en utilisant l’instruction with de Python. Dans notre fonction, nous ouvrons le fichier puis utilisons l’instruction yield afin que la fonction appelante puisse l’utiliser.

Une fois l’instruction with terminée, le contrôle revient à la fonction get_log_file() et continue avec le code suivant l’instruction yield. Cela provoque l’exécution de l’instruction finally, qui ferme le fichier. Si nous avons une erreur pendant que nous travaillons avec le fichier, elle est interceptée et l’instruction finally ferme toujours le gestionnaire de fichiers.


0 commentaire

Laisser un commentaire

Emplacement de l’avatar

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *