一、模拟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的时候运行我啊