问题描述
我们定义一个只读属性为property的方法,但此种方法,只有在访问它时才参与计算,如何把所计算的值进行缓存是今天的问题。这样不需要在每次访问时都重新计算。
解决方案
定义一个惰性属性,是快速访问存储值的最佳方案。
class lazyproperty:
def __init__(self,func):
self.func=func
def __get__(self, instance, cls):
#获取其func参数值
if instance is None:
#如果没有获取到参数,则先return到self
return self
else:
value=self.func(instance)
#如果获取到参数,则计算然后改变其值
setattr(instance,self.func.__name__,value)
return value
以上惰性属性,需要使用以下类似代码调用:
class Circle:
def __init__(self):
self.radius=radius
@lazyproperty
def area(self):
print ('Computing area')
return math.pi*self.radius**2
@lazyproperty
def perimeter(self):
print ('Computing perimeter')
return 2*math.pi*self.radius
思考如下交互式对话如何输出
c=Circle(4)
c.radius
c.area
c.area
c.radius
c.radius
注意此处代码的逻辑,虽然调用两次,但只有一个print,第二次调用使用了缓存值
但是此处需要注意的是,此效率虽然提高了,但是c.area所求出的值是可变的,即可以使用c.area=25来改变相关缓存值,这种操作极不安全。
如果需要防止得出的变量改变,应该需要使用以下效率稍低的方案。
以上操作,属于在底层字典中查询相关的函数值,所以效率极高,但使用如下方式,调用可以不改变其相关的缓存值。
def lazyproperty(func):
name='lazy_'+func.__name__
@property
def lazy(self):
if hasattr(self,name):
return getattr(self,name)
else:
value=func(self)
setattr(self,name,value)
return value
return lazy
讨论
第二种方法,实现效率稍慢的原因是,每次get操作都需要经过getter函数来处理,所以实现效率不如直接使用__get__魔法函数从python底层字典中查询相关list 或 dir迅速