描述符是python中复杂属性访问的基础。它在内部用于实现property,方法,类方法,静态方法和super类型。它是一个类可以将属性管理委托给另一个类
在每次属性查找中,这个协议的方法实际上由对象的特殊方法__getattribute__()调用。每次通过点号(instance.attrbute)函数调用执行查找,每次都会隐式的调用__getattribute__()。它会按照以下顺序查找该属性:
- 验证该属性是否为实列的类对象的数据描述符
- 如果不是,就查看该属性是否能在实列的类对象的__dic__中找到
- 最后,查看该属性是否为实列的类对象的非数据描述符
class RevealAccess(object):
'''一个数据描述符,正常设定值并返回值,同时打印出访问的信息'''
def __init__(self,initval=None,name="var"):
self.val = initval
self.name = name
def __get__(self, obj, objtype):
print("取出",self.name)
return self.val
def __set__(self, obj, val):
print("设置",self.name)
self.val = val
def __delete__(self, instance):
print("删除",self.name)
class MyClass(object):
x = RevealAccess(10,'var "X"')
y = 5
m = MyClass()
print(m.x)
m.x=99
print(m.x)
del m.x
class InitOnAccess(object):
def __init__(self,klass,*args,**kwargs):
self.klass = klass
self.args = args
self.kwargs = kwargs
self._initialized = None
def __get__(self, instance, owner):
if self._initialized is None:
print("已初始化")
self._initialized = self.klass(*self.args,**self.kwargs)
else:
print("隐藏不可见")
return self._initialized
class MyClass(object):
lazily_initialzed = InitOnAccess(list,"argument")
m = MyClass()
print(m.lazily_initialzed)
print(m.lazily_initialzed)
class Rectangle:
def __init__(self,x1,y1,x2,y2):
self.x1 = x1
self.y1 = y1
self.x2 = x2
self.y2 = y2
@property
def width(self):
"""从顶部测量的矩形高度"""
print("width.property")
return self.x2 - self.x1
@width.setter
def width(self,value):
print("width.setter")
self.x2 = self.x1 + value
@property
def height(self):
"""从顶部测量的矩形高度"""
print("height.property")
return self.y2 - self.y1
@height.setter
def height(self,value):
print("height.setter")
self.y2 = self.y1 + value
cone = Rectangle(x1=20,y1=15,x2=10,y2=5)
print(cone.width)
cone.width = 100
print(cone.width)
print('-'*20)
print(cone.height)
cone.height = 99
print(cone.height)