python基础第十七课--OOP 让属性具有惰性求值的能力(小白piao分享)
程序员文章站
2022-07-14 18:59:52
...
什么是惰性求值?
在某些场景中,我们可能更希望系统执行的高效性,在某些属性不被访问时,其不存在,当被访问时才会生成空间,另外生成后会将结果保存在缓存中,下次调用该属性会直接去取缓存中的值,而不是冗余地再去执行很多代码得到新的值。此过程,称之为惰性求值。
实例代码进行解释:
class lazyproperty:
def __init__(self,func):
self.func = func
print(self.func.__name__)
def __get__(self, instance, owner):
print(self,instance,owner)
if instance is None:
return self
else:
value = self.func(instance)
setattr(instance,self.func.__name__,value)#为对象设置属性值,当属性不存在时创建该属性
#或者:#instance.__dict__[self.func.__name__] = value
return value
#注意:此处并没有定义__set__()方法
import math
class Circle:
def __init__(self,radius):
self.radius = radius
@lazyproperty
def area(self):
print('computing area ...')
return self.radius ** 2 * math.pi
@lazyproperty
def perimetter(self):
print('compiting perimeter ...')
return 2*math.pi*self.radius
c = Circle(2.0)
print('1:',vars(c))#1: {'radius': 2.0} 底层字典中并没有area的属性
print(c.area)#当访问的数据不在底层的实例字典(instance.__dict__)中时,才会调用__get__();
# 此时实例c的底层字典通过上一行得知并没有area这个属性
#与c.area = 4.0 直接的区别是该赋值会直接将属性加入字典中。
#而惰性求值只有在访问该属性时才会将属性插入底层字典,不访问面积时会节约空间
print('2:',vars(c))#2: {'radius': 2.0, 'area': 12.566370614359172} 底层字典中才有area的属性
print(c.area)#该次打印由于已经由上次的c.area的调用导致将area的属性插入了字典中,
# 所以本次打印会直接在底层字典中寻找这个属性值,而不会再去调用area().
c.area = 25
print(c.area)#此时这种属性是可变的属性area: 4.0 -> 25
#通过如下方法可以是属性变为不可被修改的属性:
def lazyProperty(func):
name = '_lazy_'+func.__name__
print(name)
@property #相当于:lazy.getter
def lazy(self):
if hasattr(self,name):
getattr(self,name)
else:
value = func(self)
setattr(self,name,value)
print(name)
return value #相当于上述的__get__()
#注意:此处并未设置@lazy.setter,所以并不能对属性值进行设置!!!如果设置了,如下:
# 情景二:
@lazy.setter
def lazy(self,value):
setattr(self,name,value)
print(value)
return lazy
import math
class Circle:
def __init__(self,radius):
self.radius = radius
@lazyProperty
def area(self):
print('computing area ...')
return self.radius ** 2 * math.pi
@lazyProperty
def perimetter(self):
print('compiting perimeter ...')
return 2*math.pi*self.radius
c = Circle(2.0)
print(c.area)
'''
computing area ...
_lazy_area
12.566370614359172
'''
c.area = 28
'''
#如果不释放上述情景二的代码:
#则属性值不可被修改:
Traceback (most recent call last):
File "F:/PycharmProjects/class_obj/class_one.py", line 249, in <module>
c.area = 28
AttributeError: can't set attribute
Process finished with exit code 1
'''
'''
#如果释放掉上述情景二的注释:
#则会得到:
28
'''
代码来源于书籍,但是代码中的注释为自己的理解,望重点看**释内容。