2019独角兽企业重金招聘Python工程师标准>>>

定义:descriptor是一个对象属性,拥有下述的任何一个绑定方法(__set__, __get__, __delete__)。

协议:

#descriptor are only invoked for new style objects or classes.
class descriptor(object):def __set__(self, obj, value):passdef __get__(self, obj, cls):passdef __delete__(self, obj):pass

类型: data descriptor: 定义了 __set__ , __get__ 方法。

non data descriptor: 定义了__get__, 未定义__set__。

descriptor 会影响对象属性的查找顺序。总结如下:

1. instance 属性 优先于class 属性

2. 如果在class属性中发现同名的data descriptor, 那么该data descriptor会优于instance属性

附上一个属性查找逻辑代码(get):

#search an attribute 'f' of obj, type(obj)=cls
if hasattr(cls, 'f'):desc = cls.ftype = descriptor.__class__
if hasattr(type, '__get__') and hasattr(type, '__set__') or 'f' not in obj.__dict__:return type.__get__(desc, obj, 'f')
#can't found through descriptor
if 'f' in obj.__dict__:return obj.__dict__['f']
if hasattr(type, '__get__'):return type.__get__(desc, obj, 'f')
#instance's __dict__ can't found
if 'f' in obj.__class__.__dict__:return obj.__class__.__dict__['f']
#search in base classes by mro

下面我们来看一个非常有意思的示例,此例也说明了new style class 方法实现绑定的机制。

>>> class A:def fun(self):pass>>> a = A()
>>> type(A.fun), type(a.fun)
(<class 'function'>, <class 'method'>)

上图可以发现A.fun是普通的python函数对象(PyFunction_Type),而A的实例的fun(a.fun)居然变成了PyMethod_Type。

为什么会变成这样,他们之间有什么关系?下面我们慢慢道来,查看一下python源码会发现PyFunction_Type的定义如下:

PyTypeObject PyFunction_Type = {PyVarObject_HEAD_INIT(&PyType_Type, 0)"function",sizeof(PyFunctionObject),0,(destructor)func_dealloc,                   /* tp_dealloc */...func_descr_get,                             /* tp_descr_get */0,                                          /* tp_descr_set */offsetof(PyFunctionObject, func_dict),      /* tp_dictoffset */0,                                          /* tp_init */0,                                          /* tp_alloc */func_new,                                   /* tp_new */
};

可以看到类型定义里有2个特殊标记的函数指针,实际上他们分别对应着__get__,__set__的实现。至此我们明白了原来这个

PyFunction_Type的实例其实就是一个non data descriptor,对于a.fun,由于a的dict中并没有fun的属性,所以到A的dict中查找,

由于fun是一个non data descriptor属性,所以A.fun相当于 A.fun.__get__(a, A)。

下面我们看一下 func_descr_get 的实现:

/* Bind a function to an object */
static PyObject *
func_descr_get(PyObject *func, PyObject *obj, PyObject *type)
{if (obj == Py_None || obj == NULL) {Py_INCREF(func);return func;}   return PyMethod_New(func, obj);}
PyObject *
PyMethod_New(PyObject *func, PyObject *self)
{register PyMethodObject *im;if (self == NULL) {PyErr_BadInternalCall();return NULL;}im = free_list;if (im != NULL) {free_list = (PyMethodObject *)(im->im_self);PyObject_INIT(im, &PyMethod_Type);numfree--;}else {im = PyObject_GC_New(PyMethodObject, &PyMethod_Type);if (im == NULL)return NULL;}im->im_weakreflist = NULL;Py_INCREF(func);im->im_func = func;Py_XINCREF(self);im->im_self = self;_PyObject_GC_TRACK(im);return (PyObject *)im;
}

最终descriptor会返回一个PyMethod_Type的一个instance。实际上这个obj就是fun声明时的self即(a),这里你应该也明白

class 方法声明时的那个self位置参数了吧。上面这个函数变身的过程也就是属性方法的绑定。每次调用是都会进行绑定,

创建新的PyMethod_Type对象,虽然python是用了对象缓存机制,但还是不可避免的产生性能损失,对于一个频繁使用的

方法,建议大家使用unbound method版本,即A.fun(a)。

新手,如有不对还请大家指正。轻拍!

转载于:https://my.oschina.net/u/140191/blog/36741

Python descriptor相关推荐

  1. python descriptor 详解(全干货)

    目录 descriptor简介 descriptor注意事项 descriptor应用场景 regerences 正文 descriptor简介 在python中,如果一个新式类定义了__get__, ...

  2. python descript_Python descriptor.FieldDescriptor方法代码示例

    本文整理汇总了Python中google.protobuf.descriptor.FieldDescriptor方法的典型用法代码示例.如果您正苦于以下问题:Python descriptor.Fie ...

  3. 坑爹的Python陷阱(避坑指南)

    点击上方"视学算法",星标公众号 重磅干货,第一时间送达 作者:xybaby 来源:http://www.cnblogs.com/xybaby/ 我个人对陷阱的定义是这样的:代码看 ...

  4. Python基本语法(基于3.x)

    Python基本语法(基于3.x) Python的两种运行模式: 命令行模式,运行python,然后在命令行中输入python命令 程序脚本, 在命令行中输入 ./hello.py运行 Python是 ...

  5. python中文件描述符_Python中的描述符

    python中文件描述符 In Python, a class that implements a get, set or delete methods for an object is called ...

  6. 你可能不知道的10个Python Pandas的技巧和特性

    Pandas是一个基础库,用于分析.数据处理和数据科学.它是一个庞大的项目,有大量的选择和奥秘. 本教程将以Buzzfeed清单体介绍一些使用较少但惯用的Pandas功能,这些功能为你的代码提供更好的 ...

  7. python熊猫图案_Python熊猫:您可能不知道的技巧和功能

    python熊猫图案 Pandas is a foundational library for analytics, data processing, and data science. It's a ...

  8. Descriptor

    比较易懂的说明Python descriptor 官方文档 定义:符合descriptor protocol的对象(object)都称为descriptor,实际上就是实现了__get__(),__s ...

  9. python slots初探

    1. slots的用法 1.1 基本用法 之前学习python的时候,知道使用slots能够节省内存,然而却没有在实际项目中使用过,而且也不清楚为什么能够节省内存?能够节省多少内存?记忆总是那么脆弱, ...

最新文章

  1. 无线网***工具进攻方法及防范技巧
  2. 用Memcache守护程序把数据缓存到内存二
  3. 了解CUDA计算(一)
  4. (chap1 网络基础知识)网络的构成要素:(4-6)集线器和3层交换机
  5. 2.4.2 死锁的处理策略-预防死锁
  6. mysql 安装 菜鸟_mysql安装
  7. VTK:相互作用之RubberBand2DObserver
  8. SQL with(unlock)与with(readpast) (转)
  9. 【转贴】pentaho4.5汉化攻略及汉化文件
  10. java常用类介绍及源码阅读(LinkedList)
  11. 【转载】SQL Server 批量插入数据的两种方法
  12. 领导让我重写测试代码,我该怎么办?
  13. 利用辗转相除法求两个数的最大公约数
  14. Atitit Mysql查询优化器 存取类型 范围存取类型 索引存取类型 AND or的分析
  15. 常见linux服务器存储空间,全面了解linux服务器的常用命令总结
  16. 设计模式-4.行为型模式(模板方法模式/策略模式/命令模式/职责链模式/状态模式/观察者模式/中介者模式/迭代器模式/访问者模式/备忘录模式/解释器模式)
  17. 欧陆词典导入词典库(自定义英文词典)
  18. 学计算机网络布线图片,从业必看!直观的弱电各子系统图!
  19. 打印机后台程序没有运行怎么办
  20. 领英linkedin使用手册—领英好友人脉搜索方式方法

热门文章

  1. 【 C 】指针数组案例分析(const的作用)
  2. Tomcat9 访问 Manager App
  3. php超全局变量,魔术常量,魔术方法
  4. NOI2015 题解
  5. 20145234黄斐《Java程序设计》第五周
  6. centos7安装redis3.2.5
  7. 关于被代理的bean的注入的问题
  8. icinga的idoutils插件
  9. Page 的生命周期学习小结
  10. CodeSmith实用技巧(十四):使用Progress对象