Python Descriptor

在学习Python的过程中,碰到一些奇怪的结果输出,后来参考一些资料后,才知道这是Descriptor特性。现来看一下遇到的问题。


class RevealAccess(object):
def __init__(self,initval,name):
self.val=initval
self.name=name

def __get__(self,obj,objtype):
print "Retrieving:",self.name
return self.val

def __set__(self,obj,val):
print "Updating:",self.name
self.val=val

class C(object):
x=RevealAccess(10,"A test variable")





Case 1:


>>>b = C() # 类C的实例化
>>>b.x # 打印内容
Retrieving A test variable
10
>>> C.x # 输出
Retrieving A test variable
10
>>>




Case 2:


>>>b = C() # 类C的实例化
>>> b.x=100 # 赋值,注意输出结果
Updating A test variable
>>> b.x # 打印内容
Retrieving A test variable
100
>>> C.x # 打印内容
Retrieving A test variable
100
>>>




Case 3:


>>>b = C() # 类C的实例化
>>> C.x=1000 # 同样是赋值,没有输出 Updating A test variable?
>>>
>>> b.x # 没有打印输出Retrieving内容?
1000
>>> C.x # 没有打印输出Retrieving内容?
1000
>>>




Case 4:


>>>b = C() # 类C的实例化
>>> C.x = RevealAccess(999,"The second var") #同样是赋值,没有输出 Updating A test variable?
>>> b.x # 下面有打印输出内容了
Retrieving The second var
999
>>> C.x # 下面有打印输出内容了
Retrieving The second var
999
>>>



以上出现的4种不同情况,引用下文档说明:

The following methods only apply when an instance of the class containing the method (a so-called descriptor class) appears in the class dictionary of another new-style class, known as the owner class. In the examples below, ``the attribute'' refers to the attribute whose name is the key of the property in the owner class' __dict__. Descriptors can only be implemented as new-style classes themselves.



  1. __get__( self, instance, owner)

    Called to get the attribute of the owner class (class attribute access) or of an instance of that class (instance attribute access). owner is always the owner class, while instance is the instance that the attribute was accessed through, or None when the attribute is accessed through the owner. This method should return the (computed) attribute value or raise an AttributeError exception.


    ps: obj.x、class.x均会导致该调用。


  2. __set__( self, instance, value)

    Called to set the attribute on an instance instance of the owner class to a new value, value.


    ps: 仅obj.x=ttt均会导致该调用;class.x=ttt直接绑定到另外一个对象上,这里x已经不是RevealAccess的实例


  3. __delete__( self, instance)

    Called to delete the attribute on an instance instance of the owner class.





参考建议:为简化以及方面理解,在实际应用中,尽量避免obj.__dict__与class.__dict__拥有同名的属性。