注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

哈欠涟涟的博客

学习python、pyqt与django

 
 
 

日志

 
 

Python descriptor的理解  

2010-09-23 16:00:07|  分类: python |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

引用于http://www.cublog.cn/u/23216/showart_189009.html

然后修改了一点点


相对于decorator, iterator, generator, metaclass 这些概念,descriptor是python所有概念中最难理解的一个了。尽管python documentation对其描述不多(基本上是一笔带过),以至于很多人忽略了这个概念。事实上,自己以前也忽略了它,只不过最近重温python时无意间发现了他,觉得非常有必要深入研究它。

自己的理解是建立在前人的基础之上的。不过,网上关于descriptor的资料实在是有限,下面是自己认为有参考价值的几个链接:
1.http://users.rcn.com/python/download/Descriptor.htm       (最主要的参考资料)
2.http://www.python.org/peps/pep-0252.html                  (太难理解了)
3.http://www.python.org/~jeremy/weblog/030425.html
4.http://www.python.org/download/releases/2.2.2/descrintro/
5.Python25 documentation (Python Reference Manual, Chapter 3.4.2)
6.Python25的源代码

1.假如"x"是普通属性。
  每个class均有一个__dict__,该class的obj也有一个__dict__。
  1)对于obj.x,优先查找obj.__dict__["x"],如果找不到,再查找class.__dict__["x"];
  2)对于class.x,直接查找class.__dict__["x"]; 
  3)obj.__dict__与class.__dict__可以拥有同名的属性;
  4)obj.x=10,将无条件的更新obj.__dict__;class.x=10,将无条件的更新class.__dict__。

class C(object):
 x = 10

b = C()  #b.__dict__不包含"x",C.__dict__包含"x"
b.x  #10
C.x  #10
b.x=100  #b.__dict__也包含一个"x",对应的值为100;C.__dict__对应的值还是10
b.x  #100
C.x  #10
t=C()
t.x  #10
C.x=99  #C.__dict__["x"]变成了99
t.x
b.x
C.x

2.假如"x"是一个descriptor
  为简化,假设obj.__dict__没有"x"项。

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

#修改了下面一个函数,目的是为了看清楚调用时obj与objtype的值
 def __get__(self, obj, objtype):
  print 'Retrieving %s,(obj=%r,objtype=%r)' % ( self.name,obj,objtype)
  return self.val
 

#修改了下面一个函数,目的是为了看清楚调用时obj与val的值
 def __set__(self, obj, val):
  print 'Updating %s,(obj=%r,val=%r)' % (self.name,obj,val)
  self.val = val

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


>>> b = C()    # case1
>>> b.x
Retrieving A test variable,(obj=<__main__.C object at 0x02D9BD70>,objtype=<class '__main__.C'>)
10
>>> C.x
Retrieving A test variable,(obj=None,objtype=<class '__main__.C'>)
10
>>>
>>> b.x=100    # case2
Updating A test variable,(obj=<__main__.C object at 0x02D9BD70>,val=100)
#下面的输出有一定出入,不再一一修改
>>> b.x
Retrieving A test variable
100
>>> C.x
Retrieving A test variable
100
>>>
>>> C.x=1000    # case3
>>>
>>> b.x
1000
>>> C.x
1000
>>>     # case4
>>> C.x = RevealAccess(999,"The second var")
>>> b.x
Retrieving The second var
999
>>> C.x
Retrieving The second var
999
>>>

上述结果可以通过Python25 Documentation (Python Reference Manual, Chapter 3.4.2.2)解释:
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.
(注意: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.
(注意:仅obj.x=ttt均会导致该调用;class.x=ttt直接绑定到另外一个对象上)

3)__delete__( self, instance)
Called to delete the attribute on an instance instance of the owner class.


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


3.假如"x"是一个descriptor,而且obj.__dict__也有一个"x"项。非常复杂。
For instance bindings, the precedence of descriptor invocation depends on the which descriptor methods are defined. Data descriptors define both __get__() and __set__(). Non-data descriptors have just the __get__() method. Data descriptors always override a redefinition in an instance dictionary. In contrast, non-data descriptors can be overridden by instances.

详细的描述还得参考:http://users.rcn.com/python/download/Descriptor.htm

1)从该文档可以知道,descriptor与__getattribute__密切相关。基础类型object、type均定义了 __getattribute__,并有缺省实现。上面所说的descriptor的各种特性其实就是这些__getattribute__的行为。也就是说,如果自己重新定义了__getattribute__,那么这个函数具有最高的优先级。

2)另外,__getattr__/__setattr__/__delattr__也与属性的取值有关,见Python25 documentation (Python Reference Manual, Chapter 3.4.2)。它们的级别比较低。建议它们所对应的属性不要为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
 

class C(object):
 x = RevealAccess(10,"A test variable")
 def __init__(self,val):
  self.x = val

>>> b = C(100)
>>>
>>> C.x
Retrieving A test variable
10
>>> b.x
100
>>>


4.根据http://users.rcn.com/python/download/Descriptor.htm的描述,descriptor更多的被python自己用来实现一些语言上的特性。比如:function/property/staticmethod/classmethod/均是通过descriptor实现的。


  评论这张
 
阅读(395)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017