<aside> <img src="notion://custom_emoji/899aa73c-260f-813c-baa9-0003a270e9e6/29eaa73c-260f-8057-931f-007a0ac7402b" alt="notion://custom_emoji/899aa73c-260f-813c-baa9-0003a270e9e6/29eaa73c-260f-8057-931f-007a0ac7402b" width="40px" />
Indice
</aside>
Nella programmazione ad oggetti non tutto ciò che una classe sa fare deve essere per forza visibile all’esterno.
Un metodo privato serve a nascondere i dettagli interni e rendere chiaro cosa una classe fa, non come lo fa, in continuità con la filosofia dell’incapsulamento.
In Python, per convenzione, un metodo privato si scrive con due underscore iniziali: def __nome_metodo(self)
class Player:
def __init__(self, name):
self.__name = name
self.__health = 50
def take_damage(self, amount):
self.__apply_damage(amount) # metodo privato interno
print(f"{self.__name} ha {self.__health} HP.")
def __apply_damage(self, amount):
if amount < 0:
return
self.__health -= amount
if self.__health < 0:
self.__health = 0
In questo esempio, __apply_damage() è un dettaglio interno: solo Player deve usarlo.
Chi usa la classe potrà chiamare take_damage(), non __apply_damage().
<aside> 💡
Quando vuoi suddividere il codice in piccoli passi leggibili, ma non vuoi che chi usa la classe possa richiamare quei passi direttamente. Non avrebbe senso per come è pensato il flusso di esecuzione dei metodi e rischierebbe di rompere lo stato interno dell’oggetto.
</aside>
Nell’esercizio Parte 2: incapsulamento e visibilità abbiamo scritto getter e setter come metodi normali, ad esempio:
def get_health(self):
return self.__health
def set_health(self, value):
if value >= 0:
self.__health = value
In Python esiste un modo più elegante e “pythonic”: usare i decoratori @property e @nome.setter.
class Player:
def __init__(self, name, max_health):
self.__name = name
self.__max_health = max_health
self.__health = max_health
@property
def health(self):
return self.__health
@health.setter
def health(self, value):
# blocca valori fuori dai limiti
if value < 0:
self.__health = 0
elif value > self.__max_health:
self.__health = self.__max_health
else:
self.__health = value
Ora, dall’esterno si può accedere all’attributo health come se fosse una variabile:
gimli = Player("Gimli", 50)
gimli.health -= 10 # chiama automaticamente il setter
print(gimli.health) # chiama automaticamente il getter
Questa sintassi mantiene la sicurezza dei dati ma è molto più chiara da leggere.
<aside> 💻
Un decoratore in Python è una funzione speciale che modifica o estende il comportamento di un’altra funzione o metodo senza cambiarne il codice interno.
Si applica anteponendo il simbolo @ al nome del decoratore, subito sopra la definizione della funzione o del metodo:
@decoratore
def mia_funzione():
...
Nel caso delle property, i decoratori @property, @nome.setter e @nome.deleter (che non abbiamo trattato) sono usati per trasformare metodi normali in attributi gestiti automaticamente, permettendo di aggiungere logica di controllo o validazione quando un valore viene letto, modificato o cancellato.
</aside>