Python中__str__实现为何可使用self._diameter却不能用self._area?
我在学习Python的@property装饰器时遇到一个问题:创建了一个Circle类,在__str__方法里用self.area能正常运行,但换成self._area就抛出AttributeError: Circle object has no attribute _area错误,同时self._diameter却能正常访问,这是为什么?
附带的代码如下:
class Circle(object): def __init__(self, radius): self._radius=radius @property def radius(self): return self._radius @radius.setter def radius(self, radius): self._radius=radius @property def diameter(self): return self._diameter @diameter.setter def diameter(self, diameter): self._diameter=diameter @diameter.deleter def diameter(self): del self._diameter @property def area(self): self._area = self._radius**2*3.14 return self._area def __str__(self): return f'Circle has radius of {self._radius}, diameter of {self._diameter}, and area of {self.area}' c = Circle(4) c.diameter=3 print(str(c))
核心原因分析
self._diameter能访问的原因
代码里执行了c.diameter=3,这触发了diameter属性的setter方法,该方法明确给self._diameter赋了值。所以当__str__里访问self._diameter时,这个属性已经存在于实例对象中,能正常读取。self._area访问报错的原因area是只读的property(没有对应的setter方法),它的getter方法里虽然写了self._area = ...,但这个赋值操作只有在调用self.area的时候才会执行。如果直接访问self._area却从未调用过self.area,实例里根本不存在_area这个属性,就会抛出属性不存在的错误。另外,当前
area的实现存在冗余:每次调用self.area都会重新计算并覆盖self._area,完全没必要存储这个值,直接返回计算结果更合理。
修正建议
把area的property改成直接返回实时计算结果,不需要依赖_area实例属性:
@property def area(self): return self._radius ** 2 * 3.14
这样不管什么时候调用self.area,都会基于当前的_radius计算结果,既避免了冗余存储,也彻底消除了直接访问_area可能带来的错误。
内容的提问来源于stack exchange,提问作者chocalaca

