Menu
Coddy logo textTech

Сокрытие данных

Часть раздела Object Oriented Programming путешествия по Python на Coddy — урок 30 из 64.

Скрытие информации ограничивает прямой доступ к компонентам объекта, требуя, чтобы все взаимодействия происходили через четко определенные интерфейсы. Это защищает внутренние данные от несанкционированного доступа.

Вот пример класса с различными уровнями сокрытия информации:

class BankAccount:
    def __init__(self, owner, initial_balance):
        self.owner = owner                    # Публичный — можно обращаться напрямую
        self._balance = initial_balance       # Защищенный — для внутреннего использования
        self.__account_number = "ACC123456"   # Приватный — скрыт извне

Добавьте методы, обеспечивающие контролируемый доступ к скрытым данным:

class BankAccount:
    def __init__(self, owner, initial_balance):
        self.owner = owner
        self._balance = initial_balance
        self.__account_number = "ACC123456"
        
    def deposit(self, amount):
        if amount > 0:
            self._balance += amount
            return True
        return False
    
    def withdraw(self, amount):
        if amount > 0 and amount <= self._balance:
            self._balance -= amount
            return True
        return False
    
    def get_balance(self):
        return self._balance
    
    def get_account_info(self):
        # Безопасный способ отображения частичных приватных данных
        return f"Owner: {self.owner}, Account: ***{self.__account_number[-4:]}"

Используйте класс через его публичный интерфейс:

account = BankAccount("Alice", 1000)

Доступ к публичным данным напрямую:

print(account.owner)  # Alice - публичный доступ OK

Используйте контролируемые методы для защищенных данных:

print(account.get_balance())  # 1000 - контролируемый доступ
account.deposit(500)
print(account.get_balance())  # 1500 - баланс изменен безопасным способом

Попробуйте получить доступ к скрытым данным:

print(account.get_account_info())  # Владелец: Alice, Счет: ***3456
# print(account.__account_number)  # AttributeError - скрыто

Приватный атрибут подвергается искажению имен (name mangling), но технически он все еще доступен:

# Это работает, но нарушает инкапсуляцию (скрытие информации):
print(account._BankAccount__account_number)  # ACC123456

Вывод:

Alice
1000
1500
Owner: Alice, Account: ***3456
ACC123456

Ключевой момент: Скрытие информации защищает внутренние данные, делая их private или protected, а затем предоставляя контролируемый доступ через публичные методы. Это предотвращает прямое манипулирование конфиденциальными данными и обеспечивает целостность данных за счет валидации в методах доступа.

challenge icon

Задание

Средне

В этом испытании вы реализуете защищенную систему обмена сообщениями с комплексным тестированием для проверки вашего решения.

Вам нужно отредактировать securemessenger.py, чтобы реализовать класс SecureMessenger, следуя принципам сокрытия информации. Файл содержит подробные комментарии TODO, которые помогут вам в реализации.

Основные требования включают:

  • Правильная инкапсуляция учетных данных и сообщений
  • Аутентификация перед разрешением операций с сообщениями
  • Мониторинг безопасности через отслеживание попыток входа
  • Точные возвращаемые сообщения, как указано в TODO

Шпаргалка

Скрытие информации ограничивает прямой доступ к компонентам объекта с помощью модификаторов доступа:

  • public — доступен напрямую (без подчеркивания)
  • _protected — для внутреннего использования (одиночное подчеркивание)
  • __private — скрыт извне (двойное подчеркивание)
class BankAccount:
    def __init__(self, owner, initial_balance):
        self.owner = owner                    # Публичный
        self._balance = initial_balance       # Защищенный
        self.__account_number = "ACC123456"   # Приватный

Обеспечьте контролируемый доступ через публичные методы:

def get_balance(self):
    return self._balance

def deposit(self, amount):
    if amount > 0:
        self._balance += amount
        return True
    return False

Приватные атрибуты подвергаются искажению имен (name-mangling), но все еще остаются доступными:

# Нарушает скрытие информации, но работает:
print(account._BankAccount__account_number)

Попробуйте сами

from securemessenger import SecureMessenger

# Обработчик тестовых случаев
test_case = input()
if test_case == "default_test":
    # Стандартный тестовый случай из исходной задачи
    messenger = SecureMessenger("user1")
    
    # Попытка добавить сообщения до входа в систему
    print(messenger.add_message("Hello World!"))
    print(messenger.add_message("Secure Message"))
    
    # Попытка входа с неверным паролем
    print(messenger.login("wrong_pass"))
    
    # Вход с верным паролем
    print(messenger.login("secure123"))
    
    # Добавление сообщений после успешного входа
    print(messenger.add_message("Hello World!"))
    print(messenger.add_message("Secure Message"))
    
    # Получение сообщений
    print(messenger.get_messages())
    
    # Проверка попыток входа
    print(messenger.get_login_attempts())
elif test_case == "custom_password":
    # Тест с пользовательским паролем
    messenger = SecureMessenger("admin", "admin123")
    print(messenger.login("wrong_password"))
    print(messenger.login("admin123"))
    print(messenger.get_login_attempts())
elif test_case == "multiple_login_attempts":
    # Тест нескольких попыток входа
    messenger = SecureMessenger("user2")
    print(messenger.login("attempt1"))
    print(messenger.login("attempt2"))
    print(messenger.login("attempt3"))
    print(messenger.login("secure123"))
    print(messenger.get_login_attempts())
elif test_case == "message_management":
    # Тест управления сообщениями
    messenger = SecureMessenger("user3")
    print(messenger.login("secure123"))
    
    # Добавление нескольких сообщений
    messages = ["Message 1", "Message 2", "Message 3", "Message 4", "Message 5"]
    for msg in messages:
        print(messenger.add_message(msg))
    
    # Проверка всех сообщений
    print(messenger.get_messages())
elif test_case == "empty_messages":
    # Тест случая с отсутствием сообщений
    messenger = SecureMessenger("user4")
    print(messenger.login("secure123"))
    print(messenger.get_messages())
elif test_case == "access_without_login":
    # Тест доступа без входа в систему
    messenger = SecureMessenger("user5")
    print(messenger.add_message("Unauthorized message"))
    print(messenger.get_messages())
elif test_case == "attribute_privacy":
    # Тест приватности атрибутов
    messenger = SecureMessenger("user6")
    
    # Публичный атрибут
    print(f"Public username: {messenger.username}")
    
    # Приватные атрибуты - они должны вызывать AttributeError
    try:
        print(messenger.__password)
    except AttributeError as e:
        print("Password is private: AttributeError")
    
    try:
        print(messenger.__messages)
    except AttributeError as e:
        print("Messages are private: AttributeError")
    
    try:
        print(messenger.__login_attempts)
    except AttributeError as e:
        print("Login attempts are private: AttributeError")
    
    try:
        print(messenger.__is_logged_in)
    except AttributeError as e:
        print("Login status is private: AttributeError")
elif test_case == "login_logout_sequence":
    # Этот тест требует расширения класса методом logout
    # Для целей тестирования мы создадим подкласс с функционалом выхода
    class ExtendedMessenger(SecureMessenger):
        def logout(self):
            self._SecureMessenger__is_logged_in = False
            return "Logged out successfully"
    
    messenger = ExtendedMessenger("user7")
    print(messenger.login("secure123"))
    print(messenger.add_message("Test message"))
    print(messenger.get_messages())
    print(messenger.logout())
    print(messenger.get_messages())
elif test_case == "stress_test":
    # Стресс-тест с большим количеством сообщений
    messenger = SecureMessenger("user8")
    print(messenger.login("secure123"))
    
    # Добавление 100 сообщений
    for i in range(1, 101):
        messenger.add_message(f"Message {i}")
    
    # Проверка количества сообщений
    messages = messenger.get_messages()
    newline_char = '\n'  # Сохранение символа новой строки в переменную
    message_count = len(messages.split(newline_char))
    print(f"Added 100 messages. Retrieved {message_count} messages.")
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Object Oriented Programming