Questa guida copre la programmazione orientata agli oggetti (OOP) in Python e i context manager, con esempi pratici per catturare stdout/stderr e usare il pattern Tee per visualizzare e salvare l’output contemporaneamente.
In Questo Articolo
1. Classi in Python
Le classi sono il cuore della OOP. Una classe è un modello per creare oggetti con attributi (dati) e metodi (funzioni). Gli oggetti creati da una classe sono chiamati istanze. Le classi aiutano a strutturare il codice, aumentano il riuso e semplificano la manutenzione.
Struttura di una classe
class ClassName:
def __init__(self, param1, param2):
self.param1 = param1
self.param2 = param2
def method(self):
return f'{self.param1} e {self.param2}'
Punti chiave:
__init__: costruttore per inizializzare gli attributi dell’oggetto.self: riferimento all’istanza corrente.- Attributi: definiti tramite
selfe accessibili in tutti i metodi. - Metodi: operano sui dati dell’oggetto.
Creazione di oggetti
class Car:
def __init__(self, make, model, year):
self.make = make
self.model = model
self.year = year
def description(self):
return f'{self.year} {self.make} {self.model}'
my_car = Car('Toyota', 'Corolla', 2020)
print(my_car.description()) # Output: 2020 Toyota Corolla
Tipi di metodi
- Metodi di istanza — operano sull’oggetto (
self). - Metodi di classe — operano sulla classe (
cls) usando@classmethod. - Metodi statici — non dipendono né dall’istanza né dalla classe (
@staticmethod).
Ereditarietà
class Animal:
def speak(self):
return 'Voce animale'
class Dog(Animal):
def speak(self):
return 'Bau'
Polimorfismo
class Cat(Animal):
def speak(self):
return 'Miao'
cat = Cat()
print(cat.speak()) # Output: Miao
- Lo stesso metodo può avere comportamenti diversi a seconda del tipo di oggetto.
Incapsulamento
class Car:
def __init__(self, make, model):
self._make = make # attributo protetto
self._model = model
def get_make(self):
return self._make
def set_make(self, make):
self._make = make
Metodi speciali e distruttore
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f'Point({self.x}, {self.y})'
p = Point(3, 4)
print(p) # Output: Point(3, 4)
Diagramma ASCII: ereditarietà e polimorfismo
┌─────────┐
│ Animal │
└─────────┘
│ speak() │
└─────────┘
▲
┌───────┴────────┐
│ │
┌─────────┐ ┌─────────┐
│ Dog │ │ Cat │
└─────────┘ └─────────┘
│ speak() │ │ speak() │
└─────────┘ └─────────┘
2. Context manager in Python
I context manager permettono di allocare e rilasciare automaticamente risorse, anche in caso di errori.
Uso di @contextmanager
from contextlib import contextmanager
@contextmanager
def my_context():
print("Entrata nel contesto")
try:
yield "Risorsa"
finally:
print("Uscita dal contesto")
Esempio:
with my_context() as res:
print("Nel contesto:", res)
Cattura stdout/stderr e pattern Tee
Python permette di catturare stdout, stderr o entrambi, e visualizzare e catturare contemporaneamente con il pattern Tee.
3. Esempio completo: oop_and_context.py
"""
oop_and_context.py
Esempi di classi, principi OOP e context manager in Python.
Include:
- Definizioni di classi, ereditarietà, polimorfismo, incapsulamento
- Metodi di istanza, classe e statici
- Metodi speciali e distruttore
- Context manager con @contextmanager
- Cattura stdout, stderr e entrambi
- Pattern Tee: visualizzazione e cattura
- Context manager basato su classe
"""
import sys
import io
from contextlib import contextmanager
# ==========================
# Parte 1: Classi e OOP
# ==========================
class Animal:
"""Classe base per animali."""
def speak(self):
return 'Voce animale'
class Dog(Animal):
def speak(self):
return 'Bau'
class Cat(Animal):
def speak(self):
return 'Miao'
class Car:
"""Esempio di incapsulamento."""
def __init__(self, make, model, year=None):
self._make = make
self._model = model
self.year = year
def get_make(self):
return self._make
def set_make(self, make):
self._make = make
def description(self):
if self.year:
return f'{self.year} {self._make} {self._model}'
return f'{self._make} {self._model}'
class Point:
"""Classe con metodi speciali."""
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return f'Point({self.x}, {self.y})'
# ==========================
# Parte 2: Context manager
# ==========================
@contextmanager
def my_context():
print("Entrata nel contesto")
try:
yield "Risorsa"
finally:
print("Uscita dal contesto")
@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):
"""Visualizzazione e cattura contemporanea."""
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
# ==========================
# Parte 3: Context manager basato su classe
# ==========================
class OutputCapture:
"""Context manager per catturare stdout."""
def __init__(self):
self._buffer = io.StringIO()
self._old_stdout = None
def __enter__(self):
self._old_stdout = sys.stdout
sys.stdout = self._buffer
return self._buffer
def __exit__(self, exc_type, exc_val, exc_tb):
sys.stdout = self._old_stdout
return False # propagare l'eccezione
# ==========================
# Parte 4: Dimostrazioni
# ==========================
def demo_classes():
print("\n--- Dimostrazione classi ---")
dog = Dog()
cat = Cat()
print("Il cane dice:", dog.speak())
print("Il gatto dice:", cat.speak())
my_car = Car('Toyota', 'Corolla', 2020)
print("Descrizione auto:", my_car.description())
my_car.set_make('Honda')
print("Marca aggiornata:", my_car.get_make())
point = Point(3, 4)
print("Punto:", point)
def demo_context_managers():
print("\n--- Dimostrazione context manager ---")
with my_context() as res:
print("Nel contesto:", res)
with capture_stdout() as out:
print("stdout catturato")
print("Buffer:", out.getvalue().strip())
with capture_stderr() as err:
print("Va a stdout")
sys.stderr.write("Messaggio di errore\n")
print("Errore:", err.getvalue().strip())
with capture_output() as out_all:
print("stdout in cattura combinata")
sys.stderr.write("stderr in cattura combinata\n")
print("Output combinato:", out_all.getvalue().strip())
with capture_stdout_tee() as tee_out:
print("Output visibile e catturato (Tee)")
print("Buffer Tee:", tee_out.getvalue().strip())
with OutputCapture() as class_capture:
print("Cattura tramite context manager di classe")
print("Buffer context manager di classe:", class_capture.getvalue().strip())
# ==========================
# Esecuzione principale
# ==========================
if __name__ == "__main__":
demo_classes()
demo_context_managers()