第3篇:封装——公有、私有与property
封装——公有、私有与property封装是面向对象编程的核心概念之一在Python中通过命名约定和特定机制实现。以下是逐步解析1. 封装的含义封装包含两层含义数据与行为捆绑对象同时包含数据属性和操作数据的方法行为形成一个整体。信息隐藏对外只暴露必要接口隐藏内部实现细节提高代码安全性和可维护性。Python通过约定和工具如property实现这一目标。2. 公有与私有属性Python没有严格的访问控制但通过命名约定区分属性可见性。2.1 单下划线_name表示“受保护”属性暗示外部代码不应直接访问但Python不会强制阻止。classPerson:def__init__(self,name):self._namename# 受保护属性2.2 双下划线__name通过名称修饰Name Mangling避免意外访问属性名被改为_ClassName__name。classAccount:def__init__(self,balance):self.__balancebalance# 实际存储为 _Account__balanceaccAccount(100)# print(acc.__balance) # 报错AttributeErrorprint(acc._Account__balance)# 输出100不推荐直接访问双下划线主要用于防止子类属性冲突并非真正私有。3.property装饰器property将方法转为属性调用允许在访问时添加逻辑如验证、计算。classTemperature:def__init__(self,celsius):self._celsiuscelsiuspropertydefcelsius(self):returnself._celsiuscelsius.setterdefcelsius(self,value):ifvalue-273.15:raiseValueError(低于绝对零度)self._celsiusvaluepropertydeffahrenheit(self):returnself._celsius*9/532# 使用示例tTemperature(25)print(t.celsius)# 25t.celsius30# 调用setterprint(t.fahrenheit)# 86.0# t.celsius -300 # 抛出异常外部像访问属性一样使用但内部可以嵌入逻辑。4. 描述符Descriptor描述符是实现__get__,__set__,__delete__的类用于管理属性逻辑是property的底层机制。classPositiveNumber:def__set_name__(self,owner,name):self.namenamedef__get__(self,instance,owner):returninstance.__dict__.get(self.name)def__set__(self,instance,value):ifvalue0:raiseValueError(必须是正数)instance.__dict__[self.name]valueclassOrder:quantityPositiveNumber()pricePositiveNumber()def__init__(self,quantity,price):self.quantityquantity self.priceprice# 使用orderOrder(5,10)# order.quantity -1 # 抛出异常描述符使属性逻辑可重用常用于ORM框架。5. 封装的好处降低耦合调用者不依赖内部实现便于重构。增加安全性防止非法状态如负余额。简化使用用户只需了解公开接口无需深入细节。6. 实战银行账户封装完整示例展示封装的实际应用classBankAccount:def__init__(self,owner,initial_balance0):self.ownerowner self.__balanceinitial_balance# 私有属性self.__transaction_log[]# 私有日志propertydefbalance(self):returnself.__balancedefdeposit(self,amount):ifamount0:self.__balanceamount self.__log(f存款 {amount})else:raiseValueError(存款金额必须为正)defwithdraw(self,amount):if0amountself.__balance:self.__balance-amount self.__log(f取款 -{amount})else:raiseValueError(余额不足或金额无效)def__log(self,msg):# 私有方法self.__transaction_log.append(msg)defget_history(self):returnself.__transaction_log.copy()# 返回副本防止外部修改# 使用accBankAccount(Alice,100)acc.deposit(50)print(acc.balance)# 150print(acc.get_history())# [存款 50]外部只能通过公开方法交互内部状态被隐藏。7. 常见误区过度使用私有属性Python哲学是“信任开发者”通常单下划线提示足够。property与属性混淆如果同时有self._x和property的xsetter会覆盖直接赋值。描述符命名冲突需确保实例属性键名唯一如self._name。8. 小结Python通过命名约定_name,__name和property实现封装。property支持属性访问时的自定义逻辑。描述符提供可重用的属性管理机制。良好封装提升代码健壮性和可维护性。思考题User类实现要求User类包含用户名和密码密码通过property设置时进行哈希存储获取时返回掩码。importhashlibclassUser:def__init__(self,username,password):self.usernameusername self._password_hashNone# 初始化为空self.passwordpassword# 通过setter设置propertydefpassword(self):return******# 获取时返回掩码password.setterdefpassword(self,value):ifnotvalue:raiseValueError(密码不能为空)# 使用SHA-256哈希存储self._password_hashhashlib.sha256(value.encode()).hexdigest()defverify_password(self,input_password):# 验证密码input_hashhashlib.sha256(input_password.encode()).hexdigest()returninput_hashself._password_hash# 使用userUser(admin,secure123)print(user.password)# 输出: ******print(user.verify_password(secure123))# Trueprint(user.verify_password(wrong))# False此实现确保密码安全存储外部访问时只显示掩码。