
Il decoratore @setter in Python
Il decoratore @setter in Python è usato per creare una interfaccia a un attributo privato di una classe.
@setter
Questo decoratore va usato in combinazione con il decoratore @property che trasforma un metodo in un attributo "getter".
In questo modo, ogni volta che cerchi di inizializzare o modificare un valore, viene richiamata un'interfaccia per controllare e validare i dati.
Si tratta di un argomento che può sembrare un po' criptico ma è in realtà molto utile per gestire come gli attributi di una classe vengono modificati, perché ti permette di modificare il comportamento di funzioni o metodi senza alterarne direttamente il codice.
Facciamo un esempio pratico.
Supponiamo di voler creare una classe `Circle` per rappresentare un cerchio in Python.
Vogliamo però assicurarci che il raggio non sia mai impostato su un valore negativo o nullo. Per gestire questo comportamento utilizzeremo @property e @setter.
class Circle:
def __init__(self, radius):
self.radius = radius # Utilizza il setter per impostare il raggio
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value <= 0:
raise ValueError("Il raggio deve essere maggiore di zero.")
self._radius = value
In questo codice il costruttore `__init__` imposta il raggio del cerchio tramite il metodo @radius.setter che effettua un controllo sul valore prima di assegnarlo all'attributo privato `_radius`.
Nota che l'uso di _radius invece di radius all'interno della classe Circle è una convenzione comune in Python che ha a che fare con l'incapsulamento, è utile per nascondere i dettagli interni della classe e esporre solo quelle parti che sono necessarie per l'interfaccia esterna.
Se il valore è zero o negativo, viene sollevata un'eccezione.
Ad esempio, prova ad assegnare -5 al raggio.
Il costruttore passa -5 al metodo setter 'radius' che rileva un numero negativo e solleva un'eccezione.
circle = Circle(-5)
ValueError: Il raggio deve essere maggiore di zero.
L'utilizzo di `@property` e `@setter` in questo contesto ti garantisce che il raggio del cerchio sia sempre positivo.
Questo approccio ti consente di raggiungere almeno tre risultati:
- Incapsulamento: Le proprietà della classe sono protette da assegnazioni errate.
- Validazione dei dati: Puoi definire un criterio di validazione dei dati quando un attributo viene modificato.
- Interfaccia: L'uso esterno della classe rimane pulito e semplice, poiché si può accedere agli attributi direttamente.
Questi strumenti, quando usati correttamente, non solo rendono il codice più sicuro ma anche più facile da leggere e mantenere.
La chiave è capire quando e come usarli per sfruttare al meglio i loro vantaggi.
Nota che in Python l'uso del decoratore @setter è strettamente legato al decoratore @property, e non può essere usato da solo.
- Il decoratore @property viene usato per definire un metodo getter che accede a un attributo di una classe. Il metodo diventa così un attributo "pseudo" della classe, accessibile senza parentesi come se fosse un attributo normale e non un metodo.
- Il decoratore @setter è usato per definire il metodo setter corrispondente a un metodo getter definito tramite @property. Questo setter consente di modificare il valore dell'attributo, implementando eventuali controlli o validazioni necessarie.
Perché non si può usare @setter da solo
Quindi, il decoratore @setter è tecnicamente parte dell'infrastruttura creata dal decoratore @property. Quando definisci un @setter, lo fai come una seconda definizione del metodo con lo stesso nome del metodo @property, ma decorato con @nome_proprietà.setter. Se tentassi di usare @setter senza aver prima definito la proprietà con @property, Python non saprebbe a quale proprietà si riferisce il setter, causando un errore di sintassi.