5.1 Livelli di accesso
Avrai probabilmente notato il nome strano del costruttore __init__
? In futuro lo incontrerai abbastanza spesso.
In Python esistono diversi livelli di accesso agli attributi e metodi delle classi, che aiutano a controllare la visibilità e la sicurezza dei dati. I principali meccanismi di gestione dell'accesso includono l'uso di uno o due underscore (_
e __
) davanti al nome dell'attributo o del metodo.
Utilizzo delle convenzioni
Un underscore _
viene usato per attributi e metodi che non dovrebbero essere usati all'esterno della classe o del modulo. Non è proibito, ma è una convenzione che va rispettata per migliorare la leggibilità e la manutenzione del codice.
Due underscore __
vengono usati per attributi e metodi che devono essere veramente privati e protetti da accessi accidentali o intenzionali esterni. Il meccanismo di name mangling
li rende meno accessibili, ma comunque accessibili tramite nomi speciali.
Campi e metodi pubblici (public)
Attributi e metodi pubblici sono accessibili da qualsiasi parte del codice
. In Python di default tutti gli attributi e i metodi sono pubblici, se i loro nomi non iniziano con un underscore.
class MyClass:
def __init__(self):
self.public_attribute = "I am public"
def public_method(self):
return "This is a public method"
obj = MyClass()
print(obj.public_attribute) # Accessibile
print(obj.public_method()) # Accessibile
Tramite i livelli di accesso nel linguaggio Python si realizza l'incapsulamento, attraverso campi e metodi non pubblici.
5.2 Campi e metodi non pubblici
Campi e metodi protetti (protected)
Attributi e metodi protetti sono indicati con un underscore _
davanti al nome e sono destinati all'uso interno nella classe e nelle sue sottoclassi. È una convenzione che indica ai programmatori che i dati non sono destinati a essere usati al di fuori della classe.
class MyClass:
def __init__(self):
self._protected_attribute = "I am protected"
def _protected_method(self):
return "This is a protected method"
obj = MyClass()
print(obj._protected_attribute) # Accessibile, ma non raccomandato
print(obj._protected_method()) # Accessibile, ma non raccomandato
Campi e metodi privati (private)
In Python gli attributi e i metodi privati sono indicati con due underscore __
davanti al nome. Questi attributi e metodi sono destinati all'uso esclusivo all'interno della classe e il loro principale obiettivo è nascondere l'implementazione interna e proteggere i dati da modifiche o usi accidentali dall'esterno.
Per prevenire l'accesso diretto a tali attributi e metodi da codice esterno, Python applica un meccanismo speciale noto come name mangling
(offuscamento dei nomi). Questo meccanismo cambia automaticamente i nomi degli attributi privati, aggiungendo un prefisso composto dal nome della classe. Così, un attributo privato __private_attribute
nella classe MyClass
viene trasformato nel nome interno _MyClass__private_attribute
.
Questo permette di proteggere i dati da accessi non intenzionali, mantenendo però la possibilità di lavorare con essi all'interno della classe. È importante ricordare, tuttavia, che il meccanismo di "name mangling"
non è una protezione assoluta — un programmatore esperto può accedere a questi dati usando il nome modificato.
Vediamo ora come funziona in pratica:
class MyClass:
def __init__(self):
self.__private_attribute = "I am private"
def __private_method(self):
return "This is a private method"
def access_private_method(self):
return self.__private_method()
obj = MyClass()
# print(obj.__private_attribute) # Errore, non accessibile direttamente
# print(obj.__private_method()) # Errore, non accessibile direttamente
print(obj.access_private_method()) # Accessibile tramite metodo pubblico della classe
Come puoi vedere dall'esempio, l'accesso diretto agli attributi o ai metodi privati genera un errore. Ma Python mantiene la possibilità di accedervi attraverso il nome modificato. Ad esempio, puoi accedere all'attributo privato utilizzando il nome "offuscato", come mostrato qui sotto:
class MyClass:
def __init__(self):
self.__private_attribute = "I am private"
obj = MyClass()
print(obj._MyClass__private_attribute) # Stampa: I am private
Anche se l'accesso tramite nome "offuscato" è possibile, dovrebbe essere evitato, poiché viola i principi dell'incapsulamento e può portare a instabilità nel codice.
Per vedere come Python modifica i nomi degli attributi, puoi usare la funzione incorporata dir()
, che mostra tutti gli attributi e metodi disponibili di un oggetto:
class MyClass:
def __init__(self):
self.__private_attribute = "I am private"
obj = MyClass()
print(dir(obj)) # Stampa tutti gli attributi e metodi dell'oggetto, inclusi i nomi "offuscati"
L'esecuzione della funzione dir()
mostrerà un elenco di tutti gli attributi e metodi dell'oggetto, incluso _MyClass__private_attribute
, confermando il meccanismo di "name mangling"
.
5.3 Invocazione automatica dei metodi
C'era un aspetto interessante nel lavorare con i costruttori, su cui potresti aver prestato attenzione. Il metodo __init__
veniva invocato automaticamente.
Ci sono molte situazioni del genere, così come metodi per queste situazioni. Esempi:
Metodo __str__
Se il tuo oggetto ha un metodo __str__
, questo verrà invocato automaticamente quando si tenta di convertire l'oggetto in una stringa, ad esempio, quando si usano le funzioni print()
e str()
.
class Cat:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"{self.name} è {self.age} anni"
cat = Cat("Barsik", 5)
print(cat) # Stampa: Barsik è 5 anni
Metodo __len__
E se il tuo oggetto ha un metodo __len__
, verrà invocato automaticamente quando si tenta di determinare la "lunghezza" del tuo oggetto — usato dalla funzione len()
. Esempio:
class MyList:
def __init__(self, items):
self.items = items
def __len__(self):
return len(self.items)
my_list = MyList([1, 2, 3])
print(len(my_list)) # Stampa: 3
Di "metodi speciali" del genere ne incontrerai tanti nella tua vita, ma lavorarci è un piacere. Quindi preparati :)
GO TO FULL VERSION