Menu
CoddyTech

信息隐藏

本课属于 Coddy Python 学习旅程的“面向对象编程”单元。第 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,公开访问没问题

使用受控方法访问受保护的数据:

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:属性已隐藏

私有属性经过名称改写,但在技术上仍然可以访问:

# 这样可以运行,但违反了信息隐藏原则:
print(account._BankAccount__account_number)  # ACC123456

输出:

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

要点:信息隐藏通过将内部数据设为私有或受保护,然后通过公共方法提供受控访问来保护内部数据。这可以防止直接操作敏感数据,并通过访问方法中的验证确保数据完整性。

challenge icon

挑战

中等

在这个挑战中,你将实现一个安全的消息系统,并通过全面测试来验证答案。

你需要编辑 securemessenger.py,按照信息隐藏原则实现 SecureMessenger 类。文件中包含详细的 TODO 注释,可指导你完成实现。

主要要求包括:

  • 妥善封装凭据和消息
  • 进行消息操作前先完成身份验证
  • 通过跟踪登录尝试次数来监控安全性
  • 按照 TODO 中的说明准确返回消息

亲手试试

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":
    # Test message 管理
    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自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Python 在线编译器