70 lines
2.4 KiB
Python
70 lines
2.4 KiB
Python
# 第 3-2 课完整示例:Python 与 Java 的封装差异
|
||
#
|
||
# 本示例重点演示 Python 的下划线命名约定和 @property。
|
||
# 运行时会直接输出关键结论,不完整阅读讲义也能看到本课重点。
|
||
|
||
|
||
class Account:
|
||
"""表示一个账户,并演示 Python 常见的封装方式。"""
|
||
|
||
def __init__(self, owner: str, balance: float = 0.0) -> None:
|
||
# 单下划线表示“仅供内部使用”的约定,但不会禁止外部访问。
|
||
self._owner = owner
|
||
|
||
# 双下划线会触发名称改写(Name Mangling),避免子类意外覆盖同名属性。
|
||
# 它不是 Java private 那样的安全边界,也不能用于保护敏感信息。
|
||
self.__balance = 0.0
|
||
self.balance = balance
|
||
|
||
@property
|
||
def owner(self) -> str:
|
||
"""允许调用者以 account.owner 的形式读取账户所有者。"""
|
||
return self._owner
|
||
|
||
@property
|
||
def balance(self) -> float:
|
||
"""读取余额;调用时不需要写成 get_balance()。"""
|
||
return self.__balance
|
||
|
||
@balance.setter
|
||
def balance(self, value: float) -> None:
|
||
"""设置余额,并集中执行非负校验。"""
|
||
if value < 0:
|
||
raise ValueError("余额不能小于 0。")
|
||
self.__balance = value
|
||
|
||
def deposit(self, amount: float) -> None:
|
||
"""存入资金,并复用 balance 属性中的校验入口。"""
|
||
if amount <= 0:
|
||
raise ValueError("存入金额必须大于 0。")
|
||
self.balance = self.balance + amount
|
||
|
||
|
||
def main() -> None:
|
||
"""运行封装差异示例。"""
|
||
account = Account("小明", 100.0)
|
||
|
||
print("差异 1:Python 主要依靠命名约定表达成员用途。")
|
||
print(f"单下划线属性仍可访问:{account._owner}")
|
||
print()
|
||
|
||
print("差异 2:@property 让方法校验和普通属性访问可以同时存在。")
|
||
print(f"{account.owner} 当前余额:{account.balance}")
|
||
account.balance = 150.0
|
||
print(f"赋值后的余额:{account.balance}")
|
||
print()
|
||
|
||
print("差异 3:双下划线是名称改写,不是绝对私有或安全机制。")
|
||
print(f"对象中保存的实际属性名:{account.__dict__}")
|
||
print()
|
||
|
||
print("差异 4:属性赋值可以统一执行校验。")
|
||
try:
|
||
account.balance = -1.0
|
||
except ValueError as error:
|
||
print(f"非法赋值已被阻止:{error}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|