Python - Wrapper Classes (Italiano)
Introduzione alle Classi Wrapper
Ciao a tutti, futuri maghi Python! Oggi, inizieremo un avventuroso viaggio nel mondo delle classi wrapper. Non preoccupatevi se siete nuovi nella programmazione – vi guiderò passo per passo attraverso questo concetto, proprio come ho fatto per innumerevoli studenti durante gli anni della mia docenza.
Immagina di avere un bellissimo regalo, ma di volerlo rendere ancora più speciale incartandolo in un papello elegante. Questo è essenzialmente ciò che facciamo con le classi wrapper in Python – prendiamo oggetti esistenti e li "incartiamo" con funzionalità aggiuntive. Cool, vero?
Cos'sono le Classi Wrapper?
Una classe wrapper è una classe che circonda (o "incarta") un oggetto di un'altra classe o un tipo di dati primitivo. È come mettere una custodia protettiva sul vostro smartphone – il telefono funziona ancora allo stesso modo, ma ora ha alcune funzionalità e protezione aggiuntive.
Perché Utilizzare le Classi Wrapper?
- Per aggiungere nuove funzionalità agli oggetti esistenti
- Per modificare il comportamento dei metodi esistenti
- Per controllare l'accesso all'oggetto originale
Diamo un'occhiata a alcuni esempi di codice per vedere come funziona tutto questo nella pratica!
Esempio di Classe Wrapper di Base
class StringWrapper:
def __init__(self, string):
self.string = string
def get_string(self):
return self.string
def append(self, text):
self.string += text
# Utilizzo del nostro wrapper
wrapped_string = StringWrapper("Ciao")
print(wrapped_string.get_string()) # Output: Ciao
wrapped_string.append(" Mondo!")
print(wrapped_string.get_string()) # Output: Ciao Mondo!
In questo esempio, abbiamo creato una semplice classe wrapper per le stringhe. Rompiamoci il gioco:
- Definiamo una classe chiamata
StringWrapper
. - Il metodo
__init__
inizializza il nostro wrapper con una stringa. -
get_string()
ci permette di recuperare la stringa incartata. -
append()
è un nuovo metodo che aggiunge funzionalità – aggiunge testo alla nostra stringa.
Visto come abbiamo aggiunto una nuova funzionalità (append) a una stringa di base? Questa è la potenza delle classi wrapper!
Modifica del Comportamento con le Classi Wrapper
Ora, diamo un'occhiata a come possiamo modificare il comportamento dei metodi esistenti:
class ShoutingList(list):
def __getitem__(self, index):
return super().__getitem__(index).upper()
# Utilizzo del nostro wrapper
normal_list = ["ciao", "mondo", "python"]
shouting_list = ShoutingList(normal_list)
print(normal_list[0]) # Output: ciao
print(shouting_list[0]) # Output: CIAO
In questo esempio:
- Creiamo una classe
ShoutingList
che eredita dalla classe built-inlist
. - Sovrascriviamo il metodo
__getitem__
per restituire stringhe in maiuscolo. - Quando accediamo agli elementi nella nostra
ShoutingList
, questi vengono automaticamente convertiti in maiuscolo.
È come avere un amico che urla sempre quando ripete cosa dite – stesso contenuto, diversa consegna!
Controllo dell'Accesso con le Classi Wrapper
Le classi wrapper possono anche essere utilizzate per controllare l'accesso all'oggetto originale. Questo è particolarmente utile per la protezione dei dati o per implementare oggetti in sola lettura:
class ReadOnlyWrapper:
def __init__(self, data):
self._data = data
def get_data(self):
return self._data
def __setattr__(self, name, value):
if name == '_data':
super().__setattr__(name, value)
else:
raise AttributeError("Questo oggetto è di sola lettura")
# Utilizzo del nostro wrapper
data = [1, 2, 3]
read_only_data = ReadOnlyWrapper(data)
print(read_only_data.get_data()) # Output: [1, 2, 3]
read_only_data.get_data().append(4) # Questo funziona, modifica la lista originale
print(read_only_data.get_data()) # Output: [1, 2, 3, 4]
try:
read_only_data.new_attribute = "Non posso aggiungere questo"
except AttributeError as e:
print(e) # Output: Questo oggetto è di sola lettura
In questo esempio:
- Creiamo una classe
ReadOnlyWrapper
che permette solo la lettura dei dati. - Sovrascriviamo
__setattr__
per impedire l'aggiunta di nuovi attributi al wrapper. - I dati originali possono ancora essere modificati tramite
get_data()
, ma non possono essere aggiunti nuovi attributi al wrapper stesso.
È come avere una mostra museale – puoi guardare, ma non puoi toccare!
Applicazioni Pratiche delle Classi Wrapper
Le classi wrapper hanno numerose applicazioni nel mondo reale. Ecco alcuni esempi:
- Logging: Incartare oggetti per registrare chiamate di metodi o accessi agli attributi.
- Caching: Implementare un livello di caching attorno a operazioni costose.
- Validazione dell'input: Aggiungere controlli per assicurarsi che i dati soddisfino determinati criteri prima di essere utilizzati.
- Lazy loading: Posticipare la creazione di un oggetto fino a quando non è effettivamente necessario.
Implementiamo un semplice wrapper di logging:
import time
class LoggingWrapper:
def __init__(self, obj):
self.wrapped_obj = obj
def __getattr__(self, name):
original_attr = getattr(self.wrapped_obj, name)
if callable(original_attr):
def wrapper(*args, **kwargs):
start_time = time.time()
result = original_attr(*args, **kwargs)
end_time = time.time()
print(f"Chiamato {name}, ci è voluto {end_time - start_time:.2f} secondi")
return result
return wrapper
return original_attr
# Utilizzo del nostro logging wrapper
class SlowCalculator:
def add(self, x, y):
time.sleep(1) # Simula un'operazione lenta
return x + y
calc = SlowCalculator()
logged_calc = LoggingWrapper(calc)
result = logged_calc.add(3, 4)
print(f"Risultato: {result}")
Output:
Chiamato add, ci è voluto 1.00 secondi
Risultato: 7
In questo esempio:
- Creiamo un
LoggingWrapper
che incarta qualsiasi oggetto. - Intercetta le chiamate dei metodi, registra il tempo impiegato e poi chiama il metodo originale.
- Lo utilizziamo per incartare un oggetto
SlowCalculator
e registrare le sue chiamate di metodo.
È come avere un assistente personale che times tutte le tue attività e ti riporta i risultati!
Conclusione
Le classi wrapper sono uno strumento potente in Python che consente di estendere, modificare e controllare gli oggetti in modi flessibili. Sono come leArmy knives svizzere della programmazione orientata agli oggetti – versatili e incredibilmente utili nelle giuste situazioni.
Ricorda, la chiave per padroneggiare le classi wrapper è la pratica. Prova a creare i tuoi wrapper per diversi oggetti e vedi come puoi migliorare la loro funzionalità. Chi sa? Potresti finire per incartare il tuo cammino verso diventare un maestro Python!
Buon coding, e che il tuo codice sia sempre ben incartato! ??
Credits: Image by storyset