Public, Protected, Private члены класса
Часть раздела Object Oriented Programming путешествия по Python на Coddy — урок 28 из 64.
В Python существует три уровня управления доступом к членам класса: public, protected и private. Они определяют, каким образом можно получить доступ к атрибутам и методам.
Вот пример класса со всеми тремя уровнями доступа:
class BankAccount:
def __init__(self, owner, balance, account_id):
self.owner = owner # Публичный - доступен отовсюду
self._balance = balance # Защищенный - для внутреннего использования
self.__account_id = account_id # Приватный - только для класса
def deposit(self, amount): # Публичный метод
self._balance += amount
def _calculate_interest(self): # Защищенный метод
return self._balance * 0.02
def __validate_transaction(self, amount): # Приватный метод
return amount > 0 and amount <= self._balanceДоступ к публичным членам из любого места:
account = BankAccount("Alice", 1000, "12345")
print(account.owner) # Alice
account.deposit(500) # Работает нормальноДоступ к защищенным членам (одиночное подчеркивание — только соглашение):
print(account._balance) # 1500 — работает, но не рекомендуется
result = account._calculate_interest() # Работает, но не рекомендуется
print(result) # 30.0Попробуйте получить доступ к приватным членам (двойное подчеркивание — искажение имен):
# Это не сработает:
# print(account.__account_id) # AttributeError
# Но это работает (искажение имен):
print(account._BankAccount__account_id) # 12345Создайте подкласс, чтобы продемонстрировать защищенный (protected) и приватный (private) доступ:
class SavingsAccount(BankAccount):
def show_balance(self):
return self._balance # Защищенный - доступен в подклассе
def show_id(self):
# return self.__account_id # Это не сработает - приватный
return "Cannot access private member"savings = SavingsAccount("Bob", 2000, "67890")
print(savings.show_balance()) # 2000
print(savings.show_id()) # Невозможно получить доступ к приватному членуВывод:
Alice
30.0
12345
2000
Cannot access private memberКлючевой момент: Публичные члены (public) не имеют префикса и доступны отовсюду. Защищенные члены (protected) используют одно нижнее подчеркивание (_) и должны использоваться только внутри иерархии классов. Приватные члены (private) используют двойное нижнее подчеркивание (__) и подвергаются искажению имен (name-mangling) для обеспечения более строгой конфиденциальности. Управление доступом в Python основано на соглашениях, а не на строгом принуждении.
Задание
СреднеВ этом испытании вы реализуете класс BankAccount, который демонстрирует правильное использование уровней доступа public, protected и private в Python.
bankaccount.py— содержит определение класса с комментариями TODO, которые помогут вам в реализации
- Следуйте комментариям TODO в
bankaccount.py, чтобы реализовать необходимую функциональность - Реализуйте соответствующие уровни доступа (public, protected, private), как указано
- Убедитесь, что все методы правильно обрабатывают пограничные случаи (отрицательные депозиты и т. д.)
Шпаргалка
В Python существует три уровня управления доступом к членам класса:
- Public: Без префикса, доступен отовсюду
- Protected: Одиночное подчеркивание (
_), для внутреннего использования в иерархии классов - Private: Двойное подчеркивание (
__), искажение имен для доступа только внутри класса
class BankAccount:
def __init__(self, owner, balance, account_id):
self.owner = owner # Публичный
self._balance = balance # Защищенный
self.__account_id = account_id # Приватный
def deposit(self, amount): # Публичный метод
self._balance += amount
def _calculate_interest(self): # Защищенный метод
return self._balance * 0.02
def __validate_transaction(self, amount): # Приватный метод
return amount > 0 and amount <= self._balanceДоступ к членам:
account = BankAccount("Alice", 1000, "12345")
# Публичный доступ
print(account.owner) # Работает нормально
# Защищенный доступ (работает, но не рекомендуется)
print(account._balance) # 1500
# Приватный доступ (искажение имен)
print(account._BankAccount__account_id) # 12345В подклассах:
class SavingsAccount(BankAccount):
def show_balance(self):
return self._balance # Защищенный — доступен
def show_id(self):
# return self.__account_id # Приватный — недоступен
return "Cannot access private member"Попробуйте сами
from bank_account import BankAccount
# Обработчик комплексных тестовых случаев
test_case = input()
if test_case == "basic_test":
# Тест базовой функциональности
account = BankAccount("John Doe", "12345")
print(account.account_holder) # Публичный атрибут
print(account.deposit(100)) # Публичный метод
print(account.get_balance()) # Публичный метод
elif test_case == "transaction_count":
# Тестирование защищенного атрибута
account = BankAccount("Jane Smith", "67890")
account.deposit(50)
account.deposit(100)
account.deposit(200)
print(account._transaction_count) # Защищенный атрибут
print(account.get_balance())
elif test_case == "invalid_deposit":
# Тестирование валидации в методе deposit
account = BankAccount("Bob Johnson", "54321")
print(account.deposit(-50)) # Должен вернуть None
print(account.deposit(0)) # Должен вернуть None
print(account.deposit(75)) # Должен вернуть 75
print(account.get_balance())
elif test_case == "private_access":
# Тестирование доступа к приватному атрибуту
account = BankAccount("Alice Brown", "98765")
try:
print(account.__balance) # Это вызовет ошибку AttributeError
except AttributeError:
pass
try:
print(account.__account_number) # Это вызовет ошибку AttributeError
except AttributeError:
pass
print("Private attributes are not directly accessible")
account.deposit(500)
print(account.get_balance()) # Доступ через публичный метод
elif test_case == "name_mangling":
# Демонстрация искажения имен (name mangling) для приватных атрибутов
account = BankAccount("Charlie Green", "13579")
print(account._BankAccount__balance) # Доступ к приватному атрибуту через искажение имени
print(account._BankAccount__account_number) # Доступ к приватному атрибуту через искажение имени
account.deposit(300)
print(account._BankAccount__balance) # Должен показать обновленный баланс
elif test_case == "multiple_accounts":
# Тестирование нескольких аккаунтов
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":
# Тест производительности с большим количеством транзакций
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}")
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Object Oriented Programming
1Основы ООП
Внешние файлыВведение в ООПКлассы и объектыПараметр selfМетодыАтрибутыМетод-конструктор (__init__)Повторение — Простой калькулятор4Наследование
Базовое наследованиеФункция super()Переопределение методовМножественное наследованиеПорядок разрешения методовИтоги — Иерархия сотрудников7Специальные методы
Введение в магические методыПерегрузка операторовМагические методы контейнеровПовторение — Пользовательский список10Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн Strategy5Полиморфизм
Снова о переопределении методовУтиная типизацияАбстрактные классы и методыПроектирование интерфейсовИтоги — Калькулятор фигур8Продвинутые концепции ООП
Композиция против наследованияМиксиныСтатические методы и методы классаДекораторы классовМенеджеры контекста11Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн Компоновщик3Свойства классов
Переменные экземпляра и классаДекораторы свойствПриватные атрибутыИтоги — Менеджер банковского счета6Инкапсуляция
Public, Protected, Private члены классаМодификаторы доступаСокрытие данныхДекораторы property: продвинутый уровеньИтоги: Система учета студентов12Проект: Управление библиотекой
Обзор проектаКлассы Book и User