Menu
Coddy logo textTech

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._balance

Accedi ai membri pubblici da qualsiasi luogo:

account = BankAccount("Alice", 1000, "12345")
print(account.owner)        # Alice
account.deposit(500)        # Funziona correttamente

Accedi 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.0

Prova 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)  # 12345

Crea 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 privato

Output:

Alice
30.0
12345
2000
Cannot access private member

Punto 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.

challenge icon

Sfida

Medio

In 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
  1. Segui i commenti TODO in bankaccount.py per implementare le funzionalità richieste
  2. Implementa i livelli di accesso appropriati (pubblico, protetto, privato) come specificato
  3. 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}")
quiz iconMettiti alla prova

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

Esercitati da solo: Compilatore Python online