欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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
'''

        代码来源于书籍,但是代码中的注释为自己的理解,望重点看**释内容。

相关标签: python基础