我正在学习使用this的python @property
注解,我的理解是它是一个内置属性,方便访问和修改类属性,我在一些属性上使用这个注解创建了一个类,然后尝试实现str来显示所有内容。
下面,使用str()
方法显示的一切都很好,但是,当我用self._area
替换self.area
时,得到的是AttributeError: Circle object has no attribute _area
在str()
实现中,为什么允许我使用self._diameter
,而***不允许使用***self._area?
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))
1条答案
按热度按时间7uhlpewt1#
这是不起作用的,因为您(相当无意义地)只在
self.area
被访问时才懒洋洋地计算self._area
,所以如果用户提前访问c.area
,您的__str__
实现将正常工作,但在它未被访问时不工作。简单解决方案:使用一个快速计算的属性或者一个延迟计算的属性,不要混淆这两种属性。作为一个规则,你应该在
__init__
中定义(即使只是用None
来定义延迟计算的属性)all 属性;它对维护人员很友好(他们不必搜索整个类来找出属性集),而且现代CPython会为此奖励您(通过使用键共享字典来存储属性,显著降低了每个示例的内存开销,几乎将内存开销减半)。另外,提供对底层属性的完全访问的属性在Python中是没有意义的;如果您无论如何都要授予用户完全访问权限,只需将其设置为常规属性即可,这样可以节省大量的样板文件,并使代码运行得更快。在您的代码中,
radius
和diameter
都是这种情况。但在diameter
的情况下,让它管理单独的属性没有意义(diameter
的定义是半径的两倍,因此它们应该使用公共状态,_diameter
不应该存在),并且area
足够便宜,可以重新计算,它可能只是一个未缓存的属性。类的简化惯用版本如下所示:
旁注:您总是希望在一个类上实现
__repr__
,这样引用它的回溯和类似操作才有用;它非常容易编写(当__init__
参数不变时,使用type(self).__name__
使它成为子类友好的):