今天在整理以前代码的时候,发现了一个tornade写的rpc服务,看到里面用了很多的描述器,说实话,3年前的代码咋实现的,我居然也我忘了。。。。看来有必要从头再整理下了。 python的魔法函数。

长话短说,什么是描述器? 当一个物件拥有__get__()方法(必要),以及选择性的__set__()、__delete__()方法时,它可以作为描述器(Descriptor):

object.__get__(self, instance, owner) 


如果class定义了它,则这个class就可以称为描述器( descriptor )。owner是所有者的类,instance是访问descriptor的实例,如果不是通过实例访问,而是通过类访问的话,instance则为None。(descriptor的实例自己访问自己是不会触发__get__,而会触发__call__,只有descriptor作为其它类的属性才有意义。)

文章的原文地址是,http://xiaorui.cc/2015/08/30/python%E9%AD%94%E6%B3%95%E5%87%BD%E6%95%B0%E4%B8%AD%E7%9A%84%E6%8F%8F%E8%BF%B0%E5%99%A8descriptor/

在Python语言中,当描述器实际是某个类别的特性成员时,对于类别特性的取得、设定或删除,将会交由描述器来决定如何处理(除了那些内建特性,如__class__等特性之外)。例如:


我们按照上面的例子,走一遍 ! 

以上的用法是用描述器实现的get set del,他其实相当于下面操作过程:

s = Some()
Some.__dict__['x'].__get__(s,  Some);
Some.__dict__['x'].__set__(s,  10);
Some.__dict__['x'].__delete__(s);

继续,如果这样做的话:
Some.x

相当于:

Some.__dict__['x'].__get__(None, Some)

需要说明的是,在class中我们会经常使用@property属性化用法,他的原理也是描述器.

上面更多是描述器属性方面的介绍,下面我再举例说明一个描述器调用函数的方法。

在 特性名称空间 中谈过特性搜寻的顺序,依其中描述整理一下的话,特性的寻找顺序是:
在实例的__dict__中寻找是否有相符的特性名称

在产生实例的类别__dict__中寻找是否有相符的特性名称.


如果实例有定义__getattr__(),则看__getattr__()如何处理
如果实例没有定义__getattr__(),则丢出AttributeError

如果加上描述器,则寻找的顺序是:
在产生实例的类别__dict__中寻找是否有相符的特性名称。如果找到 且实际是个描述器实例(也就是具有__get__()方法),且具有__set__()或__delete__()方法,若为取值,则传回__get__ ()方法的值,若为设值,则呼叫__set__()(没有这个方法则丢出AttributeError),若为删除特性,则呼叫__delete__()(没有这个方法则丢出AttributeError),如果描述器仅具有__get__(),则先进行第2步

有点绕口,这样吧,咱们直接来个小例子,看看他的顺序,及文中魔法函数的使用方法。 

下面是直接的结果…..

可以看出,每次通过实例访问属性,都会经过__getattribute__函数。而当属性不存在时,仍然需要访问__getattribute__,不过接着要访问__getattr__。这就好像是一个异常处理函数(__getattr__ 只有在找不到他要的属性和函数时,才会触发,你在这里可以做异常处理)。 每次访问descriptor(即实现了__get__的类),都会先经过__get__函数。

有什么地方不懂,大家可以拿上面的代码来调试下,看看描述器是怎么工作的。 另外我自己觉得魔法函数中的__get__, __set__ , __delete__在开发中用的机会不多。 




对Python及运维开发感兴趣的朋友可以加QQ群 : 478476595 !!!
{ 2000人qq大群内有各厂大牛,常组织线上分享及沙龙,对高性能及分布式场景感兴趣同学欢迎加入该QQ群 }

另外如果大家觉得文章对你有些作用!   帮忙点击广告. 一来能刺激我写博客的欲望,二来好维护云主机的费用.
如果想赏钱,可以用微信扫描下面的二维码. 另外再次标注博客原地址  xiaorui.cc  ……   感谢!
暂无相关产品

发表评论