Membri pubblici, protetti e privati
Fa parte della sezione Programmazione orientata agli oggetti del percorso Python di Coddy. Lezione 28 di 64.
Python prevede tre livelli di controllo degli accessi per i membri di una classe: pubblico, protetto e privato. Questi livelli controllano come è possibile accedere agli attributi e ai metodi.
Ecco un esempio di classe con tutti e tre i livelli di accesso:
class BankAccount:
def __init__(self, owner, balance, account_id):
self.owner = owner # Pubblico - accessibile da qualsiasi punto
self._balance = balance # Protetto - per uso interno
self.__account_id = account_id # Privato - solo all'interno della classe
def deposit(self, amount): # Metodo pubblico
self._balance += amount
def _calculate_interest(self): # Metodo protetto
return self._balance * 0.02
def __validate_transaction(self, amount): # Metodo privato
return amount > 0 and amount <= self._balanceAccedi ai membri pubblici da qualsiasi luogo:
account = BankAccount("Alice", 1000, "12345")
print(account.owner) # Alice
account.deposit(500) # Funziona correttamenteAccedi ai membri protetti (trattino basso singolo - solo per convenzione):
print(account._balance) # 1500 - funziona, ma non è consigliato
result = account._calculate_interest() # Funziona, ma non è consigliato
print(result) # 30.0Prova ad accedere ai membri privati (doppio underscore: nome alterato):
# Questo non funzionerà:
# print(account.__account_id) # AttributeError
# Ma questo funziona (name mangling):
print(account._BankAccount__account_id) # 12345Crea una sottoclasse per mostrare la differenza tra accesso protetto e privato:
class SavingsAccount(BankAccount):
def show_balance(self):
return self._balance # Protetto - accessibile nella sottoclasse
def show_id(self):
# return self.__account_id # Questo non funzionerà - privato
return "Cannot access private member"savings = SavingsAccount("Bob", 2000, "67890")
print(savings.show_balance()) # 2000
print(savings.show_id()) # Impossibile accedere al membro privatoOutput:
Alice
30.0
12345
2000
Cannot access private memberPunto chiave: i membri pubblici non hanno prefissi e sono accessibili ovunque. I membri protetti usano un singolo underscore (_) e dovrebbero essere usati solo all'interno della gerarchia delle classi. I membri privati usano un doppio underscore (__) e i loro nomi vengono modificati per garantire una maggiore privacy. Il controllo degli accessi di Python si basa su convenzioni e non viene applicato rigorosamente.
Sfida
MedioIn questa sfida, implementerai una classe BankAccount che dimostra l’uso corretto dei livelli di accesso pubblico, protetto e privato in Python.
bankaccount.py- Contiene la definizione della classe con commenti TODO che guidano la tua implementazione
- Segui i commenti TODO in
bankaccount.pyper implementare le funzionalità richieste - Implementa i livelli di accesso appropriati (pubblico, protetto, privato) come specificato
- Assicurati che tutti i metodi gestiscano adeguatamente i casi limite (depositi negativi, ecc.)
Provalo tu
from bank_account import BankAccount
# Gestore completo dei casi di test
test_case = input()
if test_case == "basic_test":
# Test delle funzionalità di base
account = BankAccount("John Doe", "12345")
print(account.account_holder) # Attributo pubblico
print(account.deposit(100)) # Metodo pubblico
print(account.get_balance()) # Metodo pubblico
elif test_case == "transaction_count":
# Test dell'attributo protetto
account = BankAccount("Jane Smith", "67890")
account.deposit(50)
account.deposit(100)
account.deposit(200)
print(account._transaction_count) # Attributo protetto
print(account.get_balance())
elif test_case == "invalid_deposit":
# Test della validazione nel metodo deposit
account = BankAccount("Bob Johnson", "54321")
print(account.deposit(-50)) # Dovrebbe restituire None
print(account.deposit(0)) # Dovrebbe restituire None
print(account.deposit(75)) # Dovrebbe restituire 75
print(account.get_balance())
elif test_case == "private_access":
# Test dell'accesso agli attributi privati
account = BankAccount("Alice Brown", "98765")
try:
print(account.__balance) # Questo genererà un AttributeError
except AttributeError:
pass
try:
print(account.__account_number) # Questo genererà un AttributeError
except AttributeError:
pass
print("Private attributes are not directly accessible")
account.deposit(500)
print(account.get_balance()) # Accesso tramite un metodo pubblico
elif test_case == "name_mangling":
# Dimostrazione del name mangling per gli attributi privati
account = BankAccount("Charlie Green", "13579")
print(account._BankAccount__balance) # Accesso a un attributo privato tramite name mangling
print(account._BankAccount__account_number) # Accesso a un attributo privato tramite name mangling
account.deposit(300)
print(account._BankAccount__balance) # Dovrebbe mostrare il saldo aggiornato
elif test_case == "multiple_accounts":
# Test di più conti
account1 = BankAccount("David White", "24680")
account2 = BankAccount("Eva Black", "86420")
account3 = BankAccount("Frank Red", "97531")
account1.deposit(150)
account2.deposit(250)
account2.deposit(50)
account3.deposit(500)
account3.deposit(300)
account3.deposit(200)
print(f"{account1.account_holder}: {account1.get_balance()}")
print(f"{account2.account_holder}: {account2.get_balance()}")
print(f"{account3.account_holder}: {account3.get_balance()}")
print(f"Account 1 transactions: {account1._transaction_count}")
print(f"Account 2 transactions: {account2._transaction_count}")
print(f"Account 3 transactions: {account3._transaction_count}")
elif test_case == "stress_test":
# Test delle prestazioni con molte transazioni
account = BankAccount("Stress Tester", "11111")
for _ in range(1000):
account.deposit(1)
print(f"Final balance: {account.get_balance()}")
print(f"Transaction count: {account._transaction_count}")
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti di OOP
File esterniIntroduzione a OOPClassi vs. oggettiIl parametro selfMetodiAttributiMetodo costruttore (__init__)Riepilogo - Calcolatrice semplice4Ereditarietà
Ereditarietà di baseLa funzione super()Sovrascrittura dei metodiEreditarietà multiplaOrdine di risoluzione dei metodiRiepilogo - Gerarchia dei dipendenti7Metodi speciali
Introduzione ai metodi magiciSovraccarico degli operatoriMetodi magici dei contenitoriRiepilogo - Lista personalizzata10Modelli di progettazione Parte 1
Introduzione ai modelli di progettazioneModello SingletonModello FactoryModello ObserverModello Strategy2Decoratori
Introduzione ai decoratoriDecoratore di proprietàDecoratore di metodo staticoDecoratore di metodo di classe5Polimorfismo
Ripasso dell'override dei metodiDuck typingClassi e metodi astrattiProgettazione delle interfacceRiepilogo - Calcolatore di forme8Concetti avanzati di OOP
Composizione vs ereditarietàMixinMetodi statici e di classeDecorator di classeContext manager11Pattern di progettazione - Parte 2
Pattern dei comandiPattern adattatorePattern decoratorePattern metodo templatePattern statoPattern composito3Proprietà delle classi
Variabili di istanza e di classeDecorator delle proprietàAttributi privatiRiepilogo - Gestore di conti bancari6Incapsulamento
Membri pubblici, protetti e privatiModificatori di accessoOccultamento delle informazioniDecorator delle proprietà: avanzatiRipasso - Sistema di registri degli studenti12Progetto: Gestione della biblioteca
Panoramica del progettoClassi Libro e UtenteSistema di prestitoFunzionalità di ricercaInterfaccia amministratoreTest e integrazioneEsercitati da solo: Compilatore Python online