python魔法函数中的描述器Descriptor

今天在整理以前代码的时候,发现了一个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__在开发中用的机会不多。 



对Golang感兴趣的朋友可以加群: 278517979 !!!
另外如果大家觉得文章对你有些作用! 如果想赏钱,可以用微信扫描下面的二维码, 感谢!
另外再次标注博客原地址  xiaorui.cc

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">