
Context Manager in Python
Un context manager è un costrutto che ti permette di gestire automaticamente risorse che implementano due metodi speciali: `__enter__()` e `__exit__()`.
- `__enter__(self)`
Questo metodo viene eseguito all'inizio del blocco `with`. Serve per acquisire le risorse necessarie e può restituire un valore che sarà assegnato alla variabile dopo `as`. - `__exit__(self, exc_type, exc_val, exc_tb)`
Questo metodo viene eseguito alla fine del blocco `with`, sia che il blocco termini normalmente sia che termini a causa di un'eccezione. Serve per rilasciare le risorse acquisite.I parametri `exc_type`, `exc_val`, ed `exc_tb` forniscono informazioni sull'eccezione che potrebbe essere stata sollevata. Se il metodo ritorna `True`, l'eccezione viene soppressa.
Questi metodi vengono rispettivamente chiamati all'inizio e alla fine del contesto dall'istruzione `with`.
Puoi definire un context manager con le classi oppure con le funzioni.
A cosa servono i context manager? Sono molto utili per lavorare con le risorse che devono essere acquisite e rilasciate, come file, connessioni di rete, o blocchi di sincronizzazione. I context manage, perché ti assicurano che vengano sempre rilasciate correttamente, indipendentemente da come termina il blocco di codice associato.
Un esempio
Ecco un esempio di context manager implementato come classe tramite l'istruzione with:
class MyContextManager:
def __enter__(self):
print("Entering the context")
# Codice per acquisire la risorsa
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("Exiting the context")
# Codice per rilasciare la risorsa
if exc_type:
print(f"An exception occurred: {exc_val}")
return True # Ritorna True per sopprimere l'eccezione, False altrimenti
with MyContextManager() as manager:
# Codice all'interno del contesto
print("Inside the context")
In questo esempio abbiamo definito la classe 'MyContextManager()' con i metodi __enter__ e __exit__.
Quando chiamiamo la classe con il costrutto with, viene eseguito prima il metodo __enter__, poi il contenuto all'interno del contesto e infine il metodo __exit__
Questo è l'output del programma:
Entering the context
Inside the context
Exiting the context
Puoi realizzare i context manager anche con le funzioni
Ecco un altro esempio di context manager realizzato con una funzione.
In questo caso abbiamo ottenuto un context manager decorando la funzione con @contextmanager
from contextlib import contextmanager
@contextmanager
def my_context_manager():
print("Entering the context")
try:
yield
print("Inside the context")
finally:
print("Exiting the context")
with my_context_manager():
# Codice all'interno del contesto
print("Doing something inside the context")
In questo caso il metodo __enter__ esegue il codice che precede l'istruzione yield.
Il metodo __exit__, invece, esegue il codice che segue l'istruzione yield.
Il risultato in output è il seguente:
Entering the context
Doing something inside the context
Inside the context
Exiting the context
Nota che in caso di errore il metodo __exit__ non viene eseguito ma la clausola finally viene eseguita in ogni caso.
Quindi, se vuoi che il metodo __exit__ sia sempre eseguito, lo devi porre dentro la clausola finally.