In Python è possibile intercettare ciò che viene stampato a schermo tramite print().
Questo è utile per test, debug, logging o per sopprimere output “rumorosi”.
Ti mostrerò come farlo in modo elegante — usando solo la libreria standard e poche righe di codice.
🧩 Comprendere i Context Manager in Python
Cos’è un Context Manager?
Un Context Manager gestisce le risorse in modo sicuro e ordinato.
Definisce il comportamento durante l’inizializzazione e la pulizia di un blocco di codice.
Esempio: lavorare con i file
with open("file.txt", "w") as f:
f.write("Ciao, mondo!")
✅ Pulizia automatica: il file verrà chiuso anche se si verifica un’eccezione.
Perché i Context Manager sono utili
- Pulizia automatica – le risorse vengono rilasciate automaticamente
- Sicurezza in caso di errori – la pulizia avviene anche in caso di eccezioni
- Leggibilità del codice – logica setup/teardown in un unico punto
- Riutilizzabilità – adatto a file, locks, connessioni di rete o stdout
Uso di @contextmanager da contextlib
Il decoratore @contextmanager permette di creare context manager usando generatori:
from contextlib import contextmanager
@contextmanager
def my_context():
print("Entriamo nel contesto")
resource = "una risorsa"
try:
yield resource
finally:
print("Usciamo dal contesto")
with my_context() as res:
print("Dentro il contesto:", res)
Output:
Entriamo nel contesto
Dentro il contesto: una risorsa
Usciamo dal contesto
💡 Spiegazione:
- Codice prima di
yield→ eseguito all’ingresso - Valore di
yield→ disponibile comeas res - Codice dopo
yield→ eseguito all’uscita, anche in caso di eccezione
Perfetto per modifiche temporanee dello stato globale, ad esempio per intercettare stdout.
⚡ Riepilogo: Context Manager per stdout/stderr
| Scenario | Context Manager consigliato |
|---|---|
Intercettare solo print | capture_stdout |
| Intercettare solo errori/exception | capture_stderr |
| Intercettare stdout e stderr insieme | capture_output |
| Intercettare e mostrare simultaneamente | capture_stdout_tee / capture_output_tee |
📦 Intercettare stdout
from contextlib import contextmanager
import sys, io
@contextmanager
def capture_stdout():
old_stdout = sys.stdout
sys.stdout = buffer = io.StringIO()
try:
yield buffer
finally:
sys.stdout = old_stdout
Esempio:
with capture_stdout() as out:
print("Questa stampa è stata intercettata")
print("Intercettato:", out.getvalue())
🔧 Intercettare stderr o entrambi i flussi
Intercettare stderr
@contextmanager
def capture_stderr():
old_stderr = sys.stderr
sys.stderr = buffer = io.StringIO()
try:
yield buffer
finally:
sys.stderr = old_stderr
Intercettare stdout + stderr
@contextmanager
def capture_output():
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = sys.stderr = buffer = io.StringIO()
try:
yield buffer
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
🔀 Modalità Tee: intercettare e mostrare
class Tee(io.StringIO):
def __init__(self, original):
super().__init__()
self.original = original
def write(self, text):
self.original.write(text)
super().write(text)
def flush(self):
self.original.flush()
Context manager:
@contextmanager
def capture_stdout_tee():
old_stdout = sys.stdout
sys.stdout = tee = Tee(old_stdout)
try:
yield tee
finally:
sys.stdout = old_stdout
@contextmanager
def capture_output_tee():
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = sys.stderr = tee = Tee(old_stdout)
try:
yield tee
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
Esempio:
with capture_stdout_tee() as out:
print("Visibile e intercettato")
print("Contenuto Tee:", out.getvalue())
📦 File completo: stdout_capture.py
"""
Utility per intercettare stdout e stderr con context manager.
Supporta:
- intercettare stdout
- intercettare stderr
- intercettazione combinata
- modalità Tee
"""
import sys, io
from contextlib import contextmanager
@contextmanager
def capture_stdout():
old_stdout = sys.stdout
sys.stdout = buffer = io.StringIO()
try: yield buffer
finally: sys.stdout = old_stdout
@contextmanager
def capture_stderr():
old_stderr = sys.stderr
sys.stderr = buffer = io.StringIO()
try: yield buffer
finally: sys.stderr = old_stderr
@contextmanager
def capture_output():
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = sys.stderr = buffer = io.StringIO()
try: yield buffer
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
class Tee(io.StringIO):
def __init__(self, original):
super().__init__()
self.original = original
def write(self, text):
self.original.write(text)
super().write(text)
def flush(self):
self.original.flush()
@contextmanager
def capture_stdout_tee():
old_stdout = sys.stdout
sys.stdout = tee = Tee(old_stdout)
try: yield tee
finally: sys.stdout = old_stdout
@contextmanager
def capture_output_tee():
old_stdout = sys.stdout
old_stderr = sys.stderr
sys.stdout = sys.stderr = tee = Tee(old_stdout)
try: yield tee
finally:
sys.stdout = old_stdout
sys.stderr = old_stderr
✅ Esempi di utilizzo
from stdout_capture import capture_stdout, capture_output, capture_stdout_tee
def test_func():
print("Ciao dalla funzione")
# Intercettare stdout
with capture_stdout() as out:
test_func()
print("stdout intercettato:", out.getvalue())
# Intercettare stdout + stderr
try:
with capture_output() as out:
print("Qualcosa")
raise Exception("Oops!")
except Exception:
pass
print("Output intercettato:", out.getvalue())
# Intercettare e mostrare simultaneamente
with capture_stdout_tee() as out:
print("Visibile E intercettato")
print("Contenuto Tee:", out.getvalue())
⚠️ Consigli pratici e avvertenze
1️⃣ Output molto grande
io.StringIOpuò consumare molta memoria con grandi quantità di dati- Usa un file temporaneo:
import sys, tempfile
with tempfile.TemporaryFile(mode='w+') as tmp:
old_stdout = sys.stdout
sys.stdout = tmp
try:
print("Molti dati...")
tmp.seek(0)
captured = tmp.read()
finally:
sys.stdout = old_stdout
2️⃣ Output dai subprocess
capture_stdout()non intercetta l’output di processi esterni- Usa
subprocess.PIPE:
import subprocess
result = subprocess.run(["ls", "-la"], capture_output=True, text=True)
print(result.stdout)
3️⃣ Sicurezza nei thread
sys.stdoutesys.stderrsono globali → evitare di intercettare simultaneamente in più thread
4️⃣ Quando usare Tee
- Debug di funzioni con logging
- Strumenti CLI interattivi
- Test di integrazione con output su terminale
5️⃣ Ripristinare i flussi
- Ripristina sempre
sys.stdout/sys.stderrnelfinally
6️⃣ Evitare annidamenti profondi
- Molti intercettamenti possono mischiare l’output. Usa un contesto per scenario.
7️⃣ Best Practices nei test
- Unit test →
capture_stdout()ocapture_output() - Debug manuale → modalità Tee
- Controlla il contenuto del buffer, non effetti collaterali
Se vuoi, posso anche preparare una versione interattiva HTML/JS, dove si può eseguire il codice direttamente nel browser e vedere l’output intercettato.
Vuoi che lo faccia?