python-自制property实现延时计算
一、模拟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的时候运行我啊
浙公网安备 33010602011771号