使用@property实现私有属性时触发AttributeError的原因排查
问题分析:Topping类的AttributeError错误原因及修复
问题代码
class Topping: def __init__(self, topping_type: str, weight: float): self.topping_type = topping_type self.weight = weight @property def topping_type(self): return self.__topping_type @topping_type.setter def topping_type(self, value): if self.topping_type == "": raise ValueError("The topping type cannot be an empty string") self.__topping_type = value @property def weight(self): return self.__weight @weight.setter def weight(self, value): if value <= 0: raise ValueError("The weight cannot be less or equal to zero") self.__weight = value
触发的错误
AttributeError: 'Topping' object has no attribute '_Topping__topping_type'
错误原因
Setter方法中错误调用未初始化的私有属性
在topping_type的setter方法里,你用self.topping_type == ""做判断,但self.topping_type会直接触发@property装饰的getter方法。此时__topping_type私有属性还未被赋值(还没执行到self.__topping_type = value),自然会抛出属性不存在的错误。对Python property装饰器的理解偏差
property是用来封装私有属性的访问接口,它不会自动将self.topping_type转为私有属性——私有属性需要你主动在setter中创建并赋值。你错误地在setter里通过getter去访问尚未初始化的私有属性,才导致了异常。
修复方案
修改setter方法,直接判断传入的value参数,而非调用getter访问未初始化的属性:
class Topping: def __init__(self, topping_type: str, weight: float): self.topping_type = topping_type self.weight = weight @property def topping_type(self): return self.__topping_type @topping_type.setter def topping_type(self, value): # 直接判断传入的value参数,避免调用未初始化的getter if value == "": raise ValueError("The topping type cannot be an empty string") self.__topping_type = value @property def weight(self): return self.__weight @weight.setter def weight(self, value): if value <= 0: raise ValueError("The weight cannot be less or equal to zero") self.__weight = value
补充说明:Python中双下划线开头的属性会被自动做名称修饰(如__topping_type转为_Topping__topping_type),目的是避免子类意外覆盖,但这个修饰过程需要你主动为属性赋值才会生效。初始化时self.topping_type = topping_type会调用setter,此时正确判断传入的value并赋值给私有属性,就能完成属性的初始化。
内容的提问来源于stack exchange,提问作者Hoppa
相关产品推荐
相关产品推荐

