{count, plural, one {Corso} other {Corsi}}
Nella programmazione orientata agli oggetti (OOP), un approccio alla progettazione software, usiamo gli “oggetti” per modellare entità del mondo reale. Un oggetto è una struttura dati con attributi (dati) e metodi (funzioni) che agiscono su quei dati. I sistemi complessi possono essere più facili da progettare con gli oggetti.
Approfondisci le basi e i concetti di ingegneria del software alla base dell’OOP iniziando il nostro corso di programmazione orientata agli oggetti con Python.
L’incapsulamento è un concetto fondamentale dell’OOP. Significa raggruppare i dati e i metodi di un oggetto e nasconderne i dettagli al mondo esterno. Pensa all’incapsulamento come a un processo che crea una “capsula” (un oggetto) con i propri dati e i propri modi per manipolarli.
Lo scopo principale dell’incapsulamento è:
- Impedire l’accesso diretto ai dati (integrità dei dati).
- Semplificare il sistema mostrando solo ciò che serve (astrazione).
I metodi privati sono fondamentali per ottenere questo incapsulamento nascondendo i dettagli di implementazione interni di una classe.
Rendendo un metodo privato, comunichi ad altri programmatori che quel metodo non è pensato per essere accessibile direttamente. Questo può prevenire bug ed errori assicurando che lo stato interno di un oggetto possa essere modificato solo in modi controllati.
Qui presenteremo i metodi privati, la sintassi per definirli, come implementarli in esempi reali e le migliori pratiche per usarli.
Cosa sono i metodi privati?
I metodi privati nella programmazione orientata agli oggetti (OOP) sono funzioni all’interno di una classe progettate per l’uso interno. Incapsulano la funzionalità di una classe, assicurando che il suo funzionamento interno resti schermato dalle interazioni esterne.
Questo incapsulamento fornisce un livello di astrazione, consentendo alla classe di mantenere il controllo sul proprio stato e comportamento interni e di cambiare l’implementazione senza influenzare il codice esterno che vi fa affidamento.
In Python, la convenzione per indicare i metodi privati è anteporre al nome del metodo un singolo underscore (_) o due underscore (__). Questo funge da suggerimento per gli sviluppatori sull’ambito previsto del metodo ed è, appunto, solo una convenzione.
Sebbene questa convenzione non imponga una privacy rigorosa come in altri linguaggi, è una pratica ampiamente rispettata nella comunità Python per segnalare l’uso previsto del metodo. Più avanti approfondiremo questi aspetti in modo più completo.
La sintassi dei metodi privati
Ci sono due modi diversi per definire metodi privati, che vedremo con esempi.
Possiamo definire un metodo privato usando un singolo underscore prima del nome della funzione:
class MyClass:
def _private_method(self):
print("This is a private method")
Questa definizione è solo una convenzione per i programmatori, poiché la funzione è comunque accessibile al di fuori della classe, anche se non è consigliato.
Se è la prima volta che senti parlare di classi in Python, ti consigliamo di dare prima un’occhiata al nostro tutorial per principianti sulle Classi.
Creiamo un oggetto e proviamo ad accedere al metodo privato creato:
# Creating an object
obj = MyClass()
# Accessing from outside
obj._private_method() # Not recommended to call directly, but possible
Esiste un’altra sintassi per definire metodi privati in Python usando il doppio underscore. È così:
class MyClass:
def __private_method(self):
print("This is a private method")
obj = MyClass()
# obj.__private_method() # This will raise an AttributeError
Quando proviamo ad accedere al metodo privato dall’esterno della classe, viene generato un AttributeError, a indicare che non può essere accessibile direttamente usando il nome della funzione.
Per riassumere la sintassi dei metodi privati in Python:
- Singolo underscore: solo una convenzione per i programmatori, può essere accessibile all’esterno della funzione.
- Doppio underscore: non può essere accessibile all’esterno della funzione con il solo nome della funzione. Può comunque essere accessibile tramite il “Name Mangling”, che vedremo più avanti in questo tutorial.
Implementare i metodi privati in Python
Come esempio reale, considera una classe BankAccount sicura e facile da usare per gestire le transazioni finanziarie di un utente. I requisiti dei conti bancari sono:
- La classe deve incapsulare il saldo dell’intestatario, consentendo depositi e prelievi assicurando che il saldo non possa essere manipolato direttamente dall’esterno della classe.
- La classe dovrebbe facilitare trasferimenti sicuri tra conti, aggiornando il saldo del conto destinatario senza esporre il meccanismo interno di modifica del saldo.
- La soluzione deve aderire ai principi della programmazione orientata agli oggetti, in particolare incapsulamento e astrazione, per mantenere l’integrità dei dati del conto e fornire un’interfaccia chiara e semplice per interagire con il conto.
Ovviamente, un conto bancario necessita di più funzionalità come la verifica del saldo, la conversione di valuta e la gestione degli interessi, ma per semplicità le ignoreremo nella nostra implementazione.
Implementiamo questa soluzione e capiamo il codice.
class BankAccount:
def __init__(self, account_holder, initial_balance=0):
self.account_holder = account_holder
self.__balance = initial_balance # Private attribute
def deposit(self, amount):
if amount > 0:
self.__balance += amount
print(f"Deposited ${amount}. New balance: ${self.__balance}")
else:
print("Deposit amount must be positive.")
def withdraw(self, amount):
if 0 < amount <= self.__balance:
self.__balance -= amount
print(f"Withdrew ${amount}. New balance: ${self.__balance}")
else:
print("Insufficient funds or invalid amount.")
def __update_balance(self, amount): # Private method
self.__balance += amount
def transfer(self, amount, other_account):
if 0 < amount <= self.__balance:
self.withdraw(amount)
other_account.__update_balance(amount)
print(f"Transferred ${amount} to {other_account.account_holder}.")
else:
print("Insufficient funds or invalid amount.")
Per prima cosa creiamo una BankAccountclass, che racchiude tutti i comportamenti e le funzionalità richiesti da un oggetto BankAccount.
La classe BankAccount ha un attributo privato __balance e un metodo privato __update_balance:
- Variabile privata (
__balance): è un attributo della classeBankAccountche memorizza il saldo corrente del conto. È contrassegnato come privato anteponendo due underscore (__) al nome. Ciò significa che è destinato a essere accessibile solo all’interno della classe stessa. Ad esempio, viene modificato dai metodideposit,withdrawe__update_balance. L’accesso esterno a questo attributo non è consigliato. - Metodo privato (
__update_balance): lo scopo di questo metodo è aggiornare il saldo del conto. Viene chiamato dal metodotransferper aggiornare il saldo del conto destinatario durante un’operazione di trasferimento. L’uso di un metodo privato qui aiuta a incapsulare la logica di aggiornamento del saldo, assicurando che possa essere eseguito solo in modi controllati definiti dalla classe.
Sentiti libero di creare un nuovo file Python, copiare e incollare il codice qui sopra e qui sotto ed eseguirlo per vedere con i tuoi occhi.
# Using the Bank Account Solution
account1 = BankAccount("John Doe", 1000)
account2 = BankAccount("Jane Doe", 500)
account1.deposit(200)
account1.withdraw(100)
account1.transfer(300, account2)
Vedrai il seguente output:
Deposited $200. New balance: $1200
Withdrew $100. New balance: $1100
Withdrew $300. New balance: $800
Transferred $300 to Jane Doe.
Congratulazioni! Hai creato la tua soluzione BankAccount usando un metodo privato!
In base all’output, vediamo che durante le normali operazioni bancarie come deposito, prelievo e trasferimento di fondi, viene seguito il consueto comportamento logico di un conto bancario.
Il metodo __init__: è un metodo privato?
Probabilmente hai notato il metodo __init__ usato nell’esempio del conto bancario. Dato che usa anch’esso la sintassi con doppio underscore, potresti chiederti se sia anch’esso un metodo privato.
Il metodo __init__ non è considerato un metodo privato nello stesso modo dei metodi prefissati con doppio underscore per motivi di privacy.
Fa invece parte dei metodi speciali in Python, spesso chiamati metodi “dunder” (abbreviazione di “double underscore”), che hanno uno scopo specifico nel linguaggio. Altri esempi di tali metodi speciali includono __str__, __repr__ e __del__.
Vediamo come questo metodo speciale è stato utilizzato nel nostro esempio:
class BankAccount:
def __init__(self, account_holder, initial_balance=0):
self.account_holder = account_holder
self.__balance = initial_balance
Come vediamo, il metodo __init__ è il costruttore di una classe. Viene chiamato automaticamente quando viene creata una nuova istanza della classe e serve a inizializzare gli attributi dell’oggetto. Per la classe BankAccount, il metodo __init__ è usato per impostare i valori iniziali degli attributi account_holder e __balance.
Concetti avanzati: Name Mangling in Python
In precedenza abbiamo detto che i metodi privati in Python sono solo una convenzione e il linguaggio Python non impone rigorosamente la privacy, a differenza di altri linguaggi di programmazione.
Infatti abbiamo visto che i metodi privati possono essere accessibili direttamente quando si usa il singolo underscore, mentre l’accesso è limitato quando si usa il doppio underscore.
Perché però? A causa di un concetto chiamato “name mangling” in Python.
Quando anteponi al nome di un attributo due underscore, Python modifica automaticamente il nome aggiungendo un singolo underscore e il nome della classe prima del nome originale dell’attributo.
Questo nome modificato è il modo in cui l’attributo è memorizzato internamente all’interno della classe. Il processo di modifica del nome in questo modo è noto come name mangling.
Il name mangling è utile per due ragioni:
- Evitare conflitti di nomi: Nell’ereditarietà, se una sottoclasse definisce un attributo con lo stesso nome di un attributo nella sua superclasse, i due andrebbero in conflitto. Il name mangling aiuta a evitare questo problema assicurando che i nomi siano unici per ciascuna classe.
- Un certo grado di privacy: Sebbene Python non abbia veri attributi privati, il name mangling fornisce un modo per rendere gli attributi meno accessibili dall’esterno della classe, offrendo quindi un certo grado di privacy.
Vediamo un esempio per capire meglio.
class MyClass:
def __init__(self):
self.__private_attribute = "I am private"
def __private_method(self):
print("This is a private method")
obj = MyClass()
print(obj.__private_attribute) # This will raise an AttributeError
In questo esempio, __private_attribute e __private_method subiscono il name mangling. Internamente, sono memorizzati rispettivamente come _MyClass__private_attribute e _MyClass__private_method. Cercare di accedervi usando i loro nomi originali dall’esterno della classe produrrà un AttributeError.
Tuttavia, puoi ancora accedervi usando i loro nomi “mangled”:
print(obj._MyClass__private_attribute) # This will print "I am private"
obj._MyClass__private_method() # This will print "This is a private method"
Sebbene il name mangling renda gli attributi meno accessibili, è importante notare che non è un modo infallibile per garantire la privacy in Python. È più una convenzione per indicare che un attributo è destinato all’uso interno all’interno della classe.
Best practice per usare metodi e variabili privati
Sfruttare efficacemente metodi e variabili privati richiede il rispetto di alcune best practice. Queste pratiche aiutano a garantire che il tuo codice non sia solo funzionale, ma anche chiaro, manutenibile e sicuro.
Ecco alcune best practice da seguire:
- Usa un singolo underscore per attributi “protetti”. Se vuoi indicare che un attributo o un metodo è destinato all’uso all’interno della classe e delle sue sottoclassi ma non per l’uso esterno, anteponi un singolo underscore (
_). Questa è una convenzione in Python che segnala agli altri sviluppatori che l’attributo o il metodo è “protetto” e non dovrebbe essere accessibile direttamente. - Usa il doppio underscore per attributi “privati”. Se vuoi rendere un attributo o un metodo meno accessibile dall’esterno della classe per evitare modifiche o usi accidentali, anteponi un doppio underscore (
__). Questo attiva il name mangling e rende più difficile (ma non impossibile) accedere all’attributo o al metodo dall’esterno della classe. - Usa metodi privati per la logica interna. I metodi privati (quelli con prefisso a singolo o doppio underscore) sono un ottimo modo per incapsulare la logica interna della tua classe. Usali per eseguire attività specifiche dell’implementazione della classe che non dovrebbero essere esposte come parte dell’interfaccia pubblica della classe.
Infine, è importante essere coerenti con le tue best practice di codice. Attieniti alle convenzioni di denominazione e usale in modo coerente in tutto il tuo codebase. Questo rende il tuo codice più facile da capire e mantenere per altri sviluppatori e per il te stesso del futuro.
Conclusione
Questo tutorial ti ha introdotto ai concetti alla base dei metodi privati, alla loro sintassi e a quando puoi usarli. Abbiamo visto anche diversi esempi che mostrano come potresti usarli nel tuo prossimo progetto di coding. Infine, abbiamo esaminato alcune best practice da tenere a mente quando li utilizzi.
Per approfondire, puoi consultare la Skill Track Python Programming e il corso Object-oriented Programming in Python.
Come senior data scientist, progetto, sviluppo e distribuisco soluzioni di machine learning su larga scala per aiutare le aziende a prendere decisioni migliori basate sui dati. Come autore nell'ambito della data science, condivido ciò che ho imparato, consigli di carriera e tutorial pratici approfonditi.


