Public, Protected, Private — pamięć
Część sekcji Programowanie obiektowe ścieżki Python w Coddy. Lekcja 28 z 64.
Python ma trzy poziomy kontroli dostępu do składowych klasy: publiczny, chroniony i prywatny. Określają one, jak można uzyskać dostęp do atrybutów i metod.
Oto przykład klasy ze wszystkimi trzema poziomami dostępu:
class BankAccount:
def __init__(self, owner, balance, account_id):
self.owner = owner # Publiczny - dostępny z dowolnego miejsca
self._balance = balance # Chroniony - do użytku wewnętrznego
self.__account_id = account_id # Prywatny - dostępny tylko w obrębie klasy
def deposit(self, amount): # Metoda publiczna
self._balance += amount
def _calculate_interest(self): # Metoda chroniona
return self._balance * 0.02
def __validate_transaction(self, amount): # Metoda prywatna
return amount > 0 and amount <= self._balanceDostęp do publicznych składowych z dowolnego miejsca:
account = BankAccount("Alice", 1000, "12345")
print(account.owner) # Alice
account.deposit(500) # Działa poprawnieDostęp do składowych chronionych (pojedyncze podkreślenie — tylko konwencja):
print(account._balance) # 1500 - działa, ale nie jest zalecane
result = account._calculate_interest() # Działa, ale nie jest zalecane
print(result) # 30.0Spróbuj uzyskać dostęp do prywatnych składowych (podwójne podkreślenie — zmiana nazwy):
# To nie zadziała:
# print(account.__account_id) # AttributeError
# Ale to zadziała (modyfikowanie nazw):
print(account._BankAccount__account_id) # 12345Utwórz podklasę, aby pokazać różnicę między dostępem chronionym a prywatnym:
class SavingsAccount(BankAccount):
def show_balance(self):
return self._balance # Chroniony - dostępny w klasie pochodnej
def show_id(self):
# return self.__account_id # To nie zadziała - prywatny
return "Cannot access private member"savings = SavingsAccount("Bob", 2000, "67890")
print(savings.show_balance()) # 2000
print(savings.show_id()) # Nie można uzyskać dostępu do prywatnego elementuWynik:
Alice
30.0
12345
2000
Cannot access private memberNajważniejsza kwestia: składowe publiczne nie mają prefiksu i są dostępne wszędzie. Składowe chronione mają pojedyncze podkreślenie (_) i powinny być używane tylko w obrębie hierarchii klas. Składowe prywatne mają podwójne podkreślenie (__) i ich nazwy są modyfikowane, aby zapewnić większą prywatność. Kontrola dostępu w Pythonie opiera się na konwencji, a nie jest ściśle egzekwowana.
Wyzwanie
ŚredniW tym wyzwaniu zaimplementujesz klasę BankAccount, która demonstruje prawidłowe użycie poziomów dostępu publicznego, chronionego i prywatnego w Pythonie.
bankaccount.py— zawiera definicję klasy z komentarzami TODO wskazującymi, co należy zaimplementować
- Postępuj zgodnie z komentarzami TODO w pliku
bankaccount.py, aby zaimplementować wymaganą funkcjonalność - Zaimplementuj odpowiednie poziomy dostępu (publiczny, chroniony, prywatny) zgodnie ze specyfikacją
- Upewnij się, że wszystkie metody prawidłowo obsługują sytuacje brzegowe (ujemne wpłaty itp.)
Spróbuj swoich sił
from bank_account import BankAccount
# Kompleksowa obsługa przypadków testowych
test_case = input()
if test_case == "basic_test":
# Test podstawowej funkcjonalności
account = BankAccount("John Doe", "12345")
print(account.account_holder) # Atrybut publiczny
print(account.deposit(100)) # Metoda publiczna
print(account.get_balance()) # Metoda publiczna
elif test_case == "transaction_count":
# Testowanie atrybutu chronionego
account = BankAccount("Jane Smith", "67890")
account.deposit(50)
account.deposit(100)
account.deposit(200)
print(account._transaction_count) # Atrybut chroniony
print(account.get_balance())
elif test_case == "invalid_deposit":
# Testowanie walidacji w metodzie deposit
account = BankAccount("Bob Johnson", "54321")
print(account.deposit(-50)) # Powinno zwrócić None
print(account.deposit(0)) # Powinno zwrócić None
print(account.deposit(75)) # Powinno zwrócić 75
print(account.get_balance())
elif test_case == "private_access":
# Testowanie dostępu do atrybutu prywatnego
account = BankAccount("Alice Brown", "98765")
try:
print(account.__balance) # To spowoduje zgłoszenie wyjątku AttributeError
except AttributeError:
pass
try:
print(account.__account_number) # To spowoduje zgłoszenie wyjątku AttributeError
except AttributeError:
pass
print("Private attributes are not directly accessible")
account.deposit(500)
print(account.get_balance()) # Dostęp przez metodę publiczną
elif test_case == "name_mangling":
# Demonstracja zmiany nazw atrybutów prywatnych
account = BankAccount("Charlie Green", "13579")
print(account._BankAccount__balance) # Dostęp do atrybutu prywatnego przez zmienioną nazwę
print(account._BankAccount__account_number) # Dostęp do atrybutu prywatnego przez zmienioną nazwę
account.deposit(300)
print(account._BankAccount__balance) # Powinno wyświetlić zaktualizowane saldo
elif test_case == "multiple_accounts":
# Testowanie wielu kont
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 wydajności przy dużej liczbie transakcji
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}")
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneWprowadzenie do programowania obiektowegoKlasy a obiektyParametr selfMetodyAtrybutyMetoda konstruktora (__init__)Powtórzenie – prosty kalkulator4Dziedziczenie
Podstawy dziedziczeniaFunkcja super()Nadpisywanie metodDziedziczenie wielokrotneKolejność rozwiązywania metodPodsumowanie – hierarchia pracowników7Metody specjalne
Wprowadzenie do metod magicznychPrzeciążanie operatorówMagiczne metody kontenerówPowtórka – własna lista10Wzorce projektowe, część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec ObserverWzorzec Strategy2Dekoratory
Wprowadzenie do dekoratorówDekorator propertyDekorator metody statycznejDekorator metody klasowej5Polimorfizm
Ponowne omówienie nadpisywania metodTypowanie kaczeKlasy i metody abstrakcyjneProjektowanie interfejsówPodsumowanie — kalkulator kształtów8Zaawansowane koncepcje programowania obiektowego
Kompozycja a dziedziczenieMiksyMetody statyczne i klasoweDekoratory klasMenedżery kontekstu11Wzorce projektowe, część 2
Wzorzec PolecenieWzorzec AdapterWzorzec DekoratorWzorzec Metoda szablonowaWzorzec StanWzorzec Kompozyt3Właściwości klas
Zmienne instancji a zmienne klasoweDekoratory właściwościAtrybuty prywatnePowtórzenie — menedżer kont bankowych6Hermetyzacja
Public, Protected, Private — pamięćModyfikatory dostępuUkrywanie informacjiDekoratory właściwości — zaawansowanePodsumowanie — system ewidencji uczniów12Projekt: System zarządzania biblioteką
Przegląd projektuKlasy Book i UserSystem wypożyczeńFunkcja wyszukiwaniaInterfejs administratoraTestowanie i integracjaPoćwicz samodzielnie: Kompilator Python online