参考:https://pyzh.readthedocs.org/en/latest/Descriptor-HOW-TO-Guide.html
一个对象只要定义了 __get__(self,instance,owner),__set__(self,instance,value),__delete__(self,instance)__其中
的一个或多个,就是一个描述器。
如果一个对象同时定义了 __get__() 和 __set__(),它叫做资料描述器(data descriptor)。仅定义了 __get__() 的描述器叫非资料描述器(特别用于方法,当然其他用途也是可能的)
资料描述器和非资料描述器的区别在于:相对于实例的字典的优先级。如果实例字典中有与描述器同名的属性,如果描述器是资料描述器,优先使用资料描述器,如果是非资料描述器,优先使用字典中的属性。(译者注:这就是为何实例 a 的方法和属性重名时,比如都叫 foo Python会在访问 a.foo 的时候优先访问实例字典中的属性,因为实例函数的实现是个非资料描述器)
其中self 为描述起自身引用,instance是拥有此描述起的实例应用,owner是此描述的拥有者引用(无实例二字)。
class C(object):
def __init__(self,initval=None,name='Var'):
self.val=initval
self.name=name
def __get__(self,obj,objtype):
print(self,obj,objtype)
print('Retrieving',self.name)
return self.val
def __set__(self,obj,val):
print('Updating',self.name)
return self.name
class MyClass(object):
x=C(10," var 'x'")
y=5
m=MyClass()
print(m.x)
print(MyClass.x)
无实例时,instance为None
>>>
<__main__.C object at 0x0000000003262A20> <__main__.MyClass object at 0x000000000330B048> <class '__main__.MyClass'>
Retrieving var 'x'
10
<__main__.C object at 0x0000000003262A20> None <class '__main__.MyClass'>
Retrieving var 'x'
10
>>>
Property() 的实现:
class Property(object): "Emulate PyProperty_Type() in Objects/descrobject.c" def __init__(self, fget=None, fset=None, fdel=None, doc=None): self.fget = fget self.fset = fset self.fdel = fdel self.__doc__ = doc def __get__(self, obj, objtype=None): if obj is None: return self if self.fget is None: raise AttributeError, "unreadable attribute" return self.fget(obj) def __set__(self, obj, value): if self.fset is None: raise AttributeError, "can't set attribute" self.fset(obj, value) def __delete__(self, obj): if self.fdel is None: raise AttributeError, "can't delete attribute" self.fdel(obj)