一、模拟property

  通过描述符和类的装饰器来模拟类property

class Laproperty:

    def __init__(self, func):  # 传入area
        self.func = func

    def __get__(self, instance, owner):
        if instance is None:
            return self  # Room.area 类属性方式访问时,instance为空,模拟property,返Laproperty对象
        res = self.func(instance)
        return res


class Room:

    def __init__(self, name, width, length):
        self.name = name
        self.width = width
        self.length = length

    #@property
    @Laproperty # area = Laproperty(area)
    def area(self):
        return self.width * self.length


r = Room("长安一号", 12, 2)
print(r.area)  # 实例属性,没有,于是访问的是类属性。类属性是描述符,被Laproperty代理了,触发get方法,执行了r实例area方法

print("类属性字典", Room.__dict__)
print("实例属性字典", r.__dict__)
print(Room.area)

  运行结果

24
类属性字典 {'__module__': '__main__', '__init__': <function Room.__init__ at 0x00000000021CB840>, 'area': <__main__.Laproperty object at 0x000000000216CA20>, '__dict__': <attribute '__dict__' of 'Room' objects>, '__weakref__': <attribute '__weakref__' of 'Room' objects>, '__doc__': None}
实例属性字典 {'name': '长安一号', 'width': 12, 'length': 2}
<__main__.Laproperty object at 0x000000000216CA20>

 

 

 

二、自定制property实现延时计算功能

 

 什么是延迟计算:

    类属性的延迟计算就是将类的属性定义成一个property,只在访问的时候才会计算,而且一旦被访问后,结果将会被缓存起来,不用每次都计算。

所以解决思路就是:

    将计算的结果存放至实例的属性字典中,这样再次访问这个静态属性的时候,会直接从实例的属性字典中拿取。避免了重复计算。

class Laproperty:

    def __init__(self, func):  # 传入area
        self.func = func

    def __get__(self, instance, owner):
        if instance is None:
            return self  # Room.area 类属性方式访问时,instance为空,模拟property,返Laproperty对象
        res = self.func(instance)
        # print(self.func.__name__)
        setattr(instance, self.func.__name__, res)  # 将 area = res 添加到r实例中
        return res


class Room:

    def __init__(self, name, width, length):
        self.name = name
        self.width = width
        self.length = length

    # @property
    @Laproperty  # area = Laproperty(area)
    def area(self):
        return self.width * self.length


r = Room("长安一号", 12, 2)
print(r.area)  # 实例属性,没有,于是访问的是类属性。类属性是描述符,被Laproperty代理了,触发get方法,执行了r实例area方法
rint("类属性字典", Room.__dict__)
print("实例属性字典", r.__dict__)
print(Room.area)

  运行结果

area
24
类属性字典 {'__module__': '__main__', '__init__': <function Room.__init__ at 0x0000022E000D4950>, 'area': <__main__.Laproperty object at 0x0000022E000ED860>, '__dict__': <attribute '__dict__' of 'Room' objects>, '__weakref__': <attribute '__weakref__' of 'Room' objects>, '__doc__': None}
实例属性字典 {'name': '长安一号', 'width': 12, 'length': 2, 'area': 24}
<__main__.Laproperty object at 0x0000022E000ED860>

 

 三、 property的补充

  获取、修改、删除properperty

  没有实现setter,deleter方法时,是不能对静态属性修改、删除的


class Foo:
    @property
    def AAA(self):
        print('get的时候运行我啊')
f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA

  运行结果

Traceback (most recent call last):
  File "D:/pythonproject/work/venv/myplan/day28/property_demo.py", line 7, in <module>
    f1.AAA='aaa'
AttributeError: can't set attribute
get的时候运行我啊

  

  实现setter,deleter有两种方法

  方法1

class Foo:
    @property
    def AAA(self):
        print('get的时候运行我啊')

    @AAA.setter
    def AAA(self,val):
        print('set的时候运行我啊',val)
    @AAA.deleter
    def AAA(self):
        print('del的时候运行我啊')
#只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA

  运行结果

get的时候运行我啊
set的时候运行我啊 aaa
del的时候运行我啊

 

 

  方法2

class Foo:

    def get_AAA(self):
        print('get的时候运行我啊')
    def set_AAA(self,val):
        print('set的时候运行我啊',val)
    def del_AAA(self):
        print('del的时候运行我啊')

    AAA=property(get_AAA,set_AAA,del_AAA)
#只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA

  运行结果

get的时候运行我啊
set的时候运行我啊 aaa
del的时候运行我啊