
I metodi getter e setter in Python
In programmazione getter e setter sono due metodi speciali che ti permettono rispettivamente di leggere e modificare i valori degli attributi di un oggetto.
A cosa servono? L'uso di questi metodi è particolarmente utile per implementare l'incapsulamento, una delle caratteristiche fondamentali della programmazione orientata agli oggetti. L'incapsulamento aiuta a proteggere gli stati interni di un oggetto e a esporre solo i dati necessari all'esterno tramite un'interfaccia controllata.
Anche se Python non impone l'incapsulamento, come accade in altri linguaggi (come Java o C++), l'uso di getter e setter può aiutarti a nascondere la rappresentazione interna dei dati in un oggetto e in una classe.
Inoltre, ti consente di aggiungere delle condizioni di validazione dei dati durante l'assegnazione di valori.
Facciamo un esempio pratico.
Creiamo una semplice classe 'Persona' con due attributi.
class Persona:
nome=""
eta=0
In questo caso non ci sono metodi getter e setter.
Quando crei un'istanza puoi assegnare qualsiasi dato all'oggetto.
studente = Persona()
studente.nome="Mary"
studente.eta= -10
In questo esempio hai creato un oggetto assegnando un numero negativo (-10) all'attributo "età".
Non c'è nessun controllo sui dati al momento dell'assegnazione. Quindi, nonostante l'errore, Python accetta tutti i dati senza problemi.
Inoltre, dall'esterno chiunque può accedere agli attributi semplicemente digitando il nome degli attributi.
print(studente.eta)
-10
Per risolvere questi problemi introduciamo nella classe 'Persona' un metodo costruttore ( __init__ ) con due attributi privati '_eta' e '_nome'.
Per assicurarci che l'età non possa essere impostata a un valore negativo introduciamo un controllo aggiuntivo.
class Persona:
# metodo costruttore
def __init__(self, nome, eta):
if (eta>0):
self._nome = nome
self._eta = eta
else:
raise ValueError("L'età non può essere negativa.")
In questo modo, quando crei l'istanza devi documentare sia il nome che l'età.
Prima di assegnare i dati, l'oggetto provvede alla validazione dei dati.
Ad esempio, se ora inserisci un valore negativo all'attributo "età", Python solleva un errore.
studente = Persona("Mary", -10)
ValueError: L'età non può essere negativa.
Sei pertanto costretto a inserire un dato valido.
studente = Persona("Mary", 20)
Inoltre, non è più possibile accedere direttamente all'attributo 'nome' ed 'eta' all'interno dell'oggetto perché ora ci sono due attributi privati '_nome' ed '_eta'.
print(studente.eta)
AttributeError: 'Persona' object has no attribute 'eta'. Did you mean: '_eta'?
Ricorda comunque che l'attributo privato protegge i dati solo in parte, perché puoi comunque accedere e modificare direttamente gli attributi inserendo la loro etichetta completa come '_eta' o '_nome', senza alcun controllo sulla validazione dei dati
studente._eta=-20
A questo punto inseriamo un metodo getter per accedere al valore dell'attributo '_eta' e un metodo setter per modificare l'attributo '_eta'.
class Persona:
# metodo costruttore
def __init__(self, nome, eta):
if (eta>0):
self._nome = nome
self._eta = eta
else:
raise ValueError("L'età non può essere negativa.")
@property
def eta(self):
# getter per l'età
return self._eta
@eta.setter
def eta(self, nuova_eta):
# setter per l'età che include la validazione
if nuova_eta < 0:
raise ValueError("L'età non può essere negativa.")
self._eta = nuova_eta
Con questi metodi puoi controllare come gli attributi di un oggetto vengono impostati o restituiti, introducendo una logica di validazione o altre operazioni necessarie per mantenere la coerenza dei dati nell'oggetto.
- Il metodo getter accede all'attributo privato '_eta' e lo restituisce.
- Il metodo setter, invece, modifica l'attributo '_eta' solo se il nuovo dato supera la validazione.
Il decoratore @property trasforma un metodo in una proprietà di 'sola lettura'. Questo significa che il metodo può essere chiamato senza parentesi come se fosse un attributo. Il decoratore @eta.setter definisce il metodo setter per la proprietà. Questo metodo può includere logica di validazione.
Ad esempio, crea un'istanza della classe.
studente = Persona("Mary", 20)
Poi accedi all'attributo 'eta' tramite il metodo getter
print(studente.eta)
20
Infine, modifica l'attributo 'eta' tramite il metodo setter
studente.eta = 25
Se adesso provi a inserire un numero negativo, Python solleva un'eccezione ValueError
studente.eta = - 10
ValueError: L'età non può essere negativa.
In conclusione, l'utilizzo di getter e setter in Python fornisce un meccanismo elegante per gestire l'accesso ai dati di un oggetto.