{}const=>[]async()letfn</>var
Développement

Gestionnaires contextuels en Python : with, enter et exit

Nous analysons l'opérateur with, les méthodes enter et exit, créons nos propres gestionnaires de contexte et étudions des exemples pratiques d'utilisation pour un travail en toute sécurité avec les ressources.

К

Kodik

Auteur

6 min de lecture

Imaginez la situation : vous ouvrez un fichier, vous travaillez avec, puis vous oubliez de le fermer. Ou vous ouvrez une connexion à une base de données, et soudainement une exception se produit qui interrompt l'exécution du code avant que vous n'ayez eu le temps de libérer les ressources. Cela vous semble familier ? Les gestionnaires de contexte en Python résolvent ce problème de manière élégante et fiable.

Pourquoi avons-nous besoin de gestionnaires contextuels ?

Les gestionnaires de contexte assurent la gestion automatique des ressources. Ils garantissent qu'un certain code sera exécuté avant de commencer à travailler avec la ressource et après son achèvement, qu'une erreur se soit produite ou non.

Exemple classique sans gestionnaire de contexte :

file = open('data.txt', 'r')
try:
    content = file.read()
    # Nous travaillons avec le contenu
finally:
    file.close()  # N'oubliez pas de fermer !

Avec le gestionnaire contextuel, tout est beaucoup plus simple :

with open('data.txt', 'r') as file:
    content = file.read()
    # Le fichier se ferme automatiquement après avoir quitté le bloc

🔥 100 000+ étudiants déjà avec nous

Marre de lire la théorie ?
Il est temps de coder !

Kodik — une appli où tu apprends à coder par la pratique. Mentor IA, leçons interactives, projets réels.

🤖 IA 24/7
🎓 Certificats
💰 Gratuit
🚀 Commencer
Ont rejoint aujourd'hui

Comment fonctionne la construction with ?

Lorsque Python rencontre l'opérateur with, voici ce qui se passe :

  1. La méthode __enter__() de l'objet est appelée

  2. La valeur de retour __enter__() est affectée à la variable après as (si elle est spécifiée)

  3. Le code est exécuté à l'intérieur du bloc with

  4. Après avoir terminé le bloc (ou lorsqu'une exception se produit), la méthode __exit () est appelée

Cela garantit que le nettoyage des ressources se produira toujours, même si une erreur se produit à l'intérieur du bloc.

Créons notre propre gestionnaire contextuel

Pour créer votre propre gestionnaire contextuel, vous devez implémenter deux méthodes spéciales : __enter__ et __exit__.

Un exemple simple : le gestionnaire de connexion à la base de données

class DatabaseConnection:
    def __init__(self, db_name):
        self.db_name = db_name
        self.connection = None
    
    def __enter__(self):
        print(f"Opening connection to {self.db_name}")
        self.connection = f"Connection to {self.db_name}"
        return self.connection
    
    def __exit__(self, exc_type, exc_value, traceback):
        print(f"Closing connection to {self.db_name}")
        if exc_type is not None:
            print(f"An error occurred: {exc_type.__name__}: {exc_value}")
        return False  # L'exception sera transmise

# Utilisation
with DatabaseConnection("users_db") as conn:
    print(f"We work with: {conn}")
    # Voici votre code de travail avec la base de données

Conclusion :

Открываем соединение с users_db
Работаем с: Connection to users_db
Закрываем соединение с users_db

Méthode __enter ()

La méthode __enter__() est appelée lors de l'entrée dans le contexte. Elle peut :

  • Initialiser les ressources

  • Établir des connexions

  • Saisir les blocages

  • Retourner l'objet pour le travail (qui sera disponible via as)

def __enter__(self):
    # Préparation des ressources
    self.resource = self.acquire_resource()
    return self.resource  # Cette valeur sera affectée à la variable après 'as'

Important : la méthode peut renvoyer n'importe quel objet, y compris self. Si vous n'avez pas besoin d'une valeur de retour, vous pouvez simplement utiliser with sans as.

Méthode __exit__ (exc_type, exc_value, traceback)

La méthode __exit__() est appelée lors de la sortie du contexte et prend trois arguments :

  • exc_type — type d'exception (ou None, s'il n'y a pas eu d'exception)

  • exc_value — objet d'exception

  • traceback — objet traceback pour l'exception

La valeur renvoyée détermine si l'exception est supprimée :

  • True — l'exception est supprimée (n'est pas transmise)

  • False ou None — l'exception est réacheminée

Exemple de gestion des exceptions

class ErrorHandler:
    def __init__(self, suppress_errors=False):
        self.suppress_errors = suppress_errors
    
    def __enter__(self):
        print("Starting execution")
        return self
    
    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is not None:
            print(f"Caught exception: {exc_type.__name__}")
            if self.suppress_errors:
                print("Exception suppressed")
                return True  # Suppression de l'exception
        print("Completing")
        return False  # Nous lançons une exception

# L'exception sera supprimée
with ErrorHandler(suppress_errors=True):
    print("Executing code")
    raise ValueError("Something went wrong!")
    print("This line will not be executed")

print("The program continues to work")

Exemples pratiques d'utilisation

Minuteur d'exécution du code

import time

class Timer:
    def __enter__(self):
        self.start = time.time()
        return self
    
    def __exit__(self, *args):
        self.end = time.time()
        self.elapsed = self.end - self.start
        print(f"Execution time: {self.elapsed:.4f} seconds")

with Timer():
    # Mesurer le temps d'exécution
    total = sum(range(1000000))

Changement temporaire de répertoire

import os

class ChangeDirectory:
    def __init__(self, new_path):
        self.new_path = new_path
        self.saved_path = None
    
    def __enter__(self):
        self.saved_path = os.getcwd()
        os.chdir(self.new_path)
        return self
    
    def __exit__(self, *args):
        os.chdir(self.saved_path)

with ChangeDirectory('/tmp'):
    print(f"Current directory: {os.getcwd()}")
    # Nous travaillons dans /tmp

print(f"Returned to: {os.getcwd()}")

Gestion des transactions

class Transaction:
    def __init__(self, connection):
        self.connection = connection
    
    def __enter__(self):
        self.connection.begin()
        return self.connection
    
    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type is None:
            self.connection.commit()
            print("Transaction confirmed")
        else:
            self.connection.rollback()
            print("Transaction rolled back")
        return False

# Utilisation
# with Transaction(db_connection) as conn:
#     conn.execute("INSERT INTO users VALUES (...)")
# # Si une erreur se produit, les modifications seront annulées

Module contextlib — gestionnaires de contexte sans classes

Python fournit le module contextlib, qui permet de créer des gestionnaires de contexte plus facilement à l'aide du décorateur @contextmanager :

from contextlib import contextmanager

@contextmanager
def managed_file(filename, mode):
    print(f"Opening file {filename}")
    file = open(filename, mode)
    try:
        yield file  # Tout jusqu'à yield est __enter__
    finally:
        print(f"Closing file {filename}")
        file.close()  # Tout après yield est __exit__

with managed_file('test.txt', 'w') as f:
    f.write('Hello, world!')

Le mot-clé yield sépare la logique : le code qui le précède est exécuté lors de l'entrée dans le contexte, le code qui le suit est exécuté lors de la sortie.

Suppression des exceptions avec contextlib.suppress

from contextlib import suppress

# Ignorer FileNotFoundError
with suppress(FileNotFoundError):
    os.remove('non-existent_file.txt')

print("The program continues to work")

Plusieurs gestionnaires contextuels

Python permet d'utiliser plusieurs gestionnaires de contexte dans un seul opérateur with :

with open('input.txt', 'r') as infile, open('output.txt', 'w') as outfile:
    content = infile.read()
    outfile.write(content.upper())

Cela équivaut à des blocs imbriqués :

with open('input.txt', 'r') as infile:
    with open('output.txt', 'w') as outfile:
        content = infile.read()
        outfile.write(content.upper())

Quand utiliser les gestionnaires contextuels ?

Les gestionnaires contextuels sont idéaux pour les situations où une opération de « réglage/nettoyage » est nécessaire :

  • Gestion des fichiers

  • Gestion des connexions à la base de données

  • Verrouillages dans les applications multithread

  • Changement temporaire de l'état du système

  • Gestion des transactions

  • Mesure du temps d'exécution

  • Journalisation de l'entrée et de la sortie des blocs de code

Conseils et meilleures pratiques

Libérez toujours les ressources dans __exit__(). Même si une exception s'est produite, la méthode __exit__() est appelée, elle doit donc nettoyer correctement les ressources.

Utilisez contextlib pour les cas simples. Si vous n'avez pas besoin de toute la puissance de la classe, le décorateur @contextmanager simplifiera considérablement le code.

Soyez prudent avec la suppression des exceptions. Retournez True de __exit__() uniquement lorsque vous êtes sûr que l'exception a été traitée correctement.

Les gestionnaires de contexte peuvent être réutilisés. Le même objet de gestionnaire de contexte peut être utilisé plusieurs fois s'il réinitialise correctement l'état.

Testez le comportement en cas d'exceptions. Assurez-vous que votre gestionnaire de contexte fonctionne correctement à la fois en mode normal et en cas d'erreurs.

Les gestionnaires de contexte rendent votre code plus propre, plus sûr et plus fiable. Ils éliminent la nécessité de se souvenir du nettoyage manuel des ressources et garantissent que tout est fait correctement, même si quelque chose ne va pas. C'est un exemple de la façon dont Python aide les développeurs à écrire un meilleur code avec moins d'effort.

Annexe Code propose des cours structurés pour les développeurs débutants en Python, JavaScript, HTML, CSS et autres technologies. La formation est structurée de manière à ce que vous puissiez progressivement maîtriser la matière, du plus simple au plus complexe.

Rejoignez notre Chaîne Telegram, où vous trouverez le soutien de la communauté, vous pourrez poser des questions et obtenir de l'aide pour apprendre la programmation. Apprendre ensemble est plus facile et plus intéressant !

🎯Arrête de reporter

Tu as aimé l'article ?
Place à la pratique !

Avec Kodik, tu ne lis pas seulement — tu codes immédiatement. Théorie + pratique = vraies compétences.

Pratique instantanée
🧠L'IA explique le code
🏆Certificat

Sans inscription • Sans carte