本文我们介绍如何定义 Python 只读属性,以及使用只读属性定义计算属性。
只读属性简介
定义只读属性的方法就是创建只有 getter 方法的属性。不过,这种方法定义的不是真正意义上的只读属性,因为我们总是可以访问和修改底层的属性。
只读属性通常用于某些特定场景,例如定义计算属性。
以下示例定义了一个类 Circle,包含 radius 属性和 area() 方法:
import math
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return math.pi * self.radius ** 2
下面的代码创建了一个新的 Circle 对象,并且返回了它的面积:
c = Circle(10)
print(c.area())
输出结果如下:
314.1592653589793
以上代码可以正常运行。但是,如果 area 是 Circle 对象的一个属性,而不是方法的话,会更加符合我们的常识。为了将 area() 方法修改为属性,可以使用 @property 装饰器:
import math
class Circle:
def __init__(self, radius):
self.radius = radius
@property
def area(self):
return math.pi * self.radius ** 2
c = Circle(10)
print(c.area)
area 基于 radius 属性的计算结果,因此通常被称为计算属性。
缓存计算属性
假如我们创建了一个新的 Circle 对象,并且多次访问 area 属性。每次访问时,都需要重新计算面积,这种方式不够高效。
为了提高性能,我们只需要在半径发生变化时重新计算圆的面积。如果半径没有改变,我们可以重用之前的面积。为此,我们可以使用以下缓存技术:
- 首先,计算面积并将其缓存。
- 然后,当半径发生改变时重新计算面积;否则直接从缓存中返回面积。
以下代码重新定义了 Circle 类,对 area 属性进行了缓存处理:
import math
class Circle:
def __init__(self, radius):
self._radius = radius
self._area = None
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
if value < 0:
raise ValueError('Radius must be positive')
if value != self._radius:
self._radius = value
self._area = None
@property
def area(self):
if self._area is None:
self._area = math.pi * self.radius ** 2
return self._area
首先,在 __init__ 方法中将 _area 设置为 None。_area 属性就是存储面积的缓存。
其次,如果半径发生变化(通过 setter 方法),将 _area 重置为 None。
最后,定义计算属性 area。如果 _area 不为 None,返回它的值;否则,计算面积并将其保存到 _area,返回数据。
总结
- 通过只定义 getter 方法的方式创建只读属性。
- 使用计算属性创建更加自然的类属性。
- 使用缓存改进计算属性的性能。
|