Python descriptor
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相关推荐
- python descriptor 详解(全干货)
目录 descriptor简介 descriptor注意事项 descriptor应用场景 regerences 正文 descriptor简介 在python中,如果一个新式类定义了__get__, ...
- python descript_Python descriptor.FieldDescriptor方法代码示例
本文整理汇总了Python中google.protobuf.descriptor.FieldDescriptor方法的典型用法代码示例.如果您正苦于以下问题:Python descriptor.Fie ...
- 坑爹的Python陷阱(避坑指南)
点击上方"视学算法",星标公众号 重磅干货,第一时间送达 作者:xybaby 来源:http://www.cnblogs.com/xybaby/ 我个人对陷阱的定义是这样的:代码看 ...
- Python基本语法(基于3.x)
Python基本语法(基于3.x) Python的两种运行模式: 命令行模式,运行python,然后在命令行中输入python命令 程序脚本, 在命令行中输入 ./hello.py运行 Python是 ...
- python中文件描述符_Python中的描述符
python中文件描述符 In Python, a class that implements a get, set or delete methods for an object is called ...
- 你可能不知道的10个Python Pandas的技巧和特性
Pandas是一个基础库,用于分析.数据处理和数据科学.它是一个庞大的项目,有大量的选择和奥秘. 本教程将以Buzzfeed清单体介绍一些使用较少但惯用的Pandas功能,这些功能为你的代码提供更好的 ...
- python熊猫图案_Python熊猫:您可能不知道的技巧和功能
python熊猫图案 Pandas is a foundational library for analytics, data processing, and data science. It's a ...
- Descriptor
比较易懂的说明Python descriptor 官方文档 定义:符合descriptor protocol的对象(object)都称为descriptor,实际上就是实现了__get__(),__s ...
- python slots初探
1. slots的用法 1.1 基本用法 之前学习python的时候,知道使用slots能够节省内存,然而却没有在实际项目中使用过,而且也不清楚为什么能够节省内存?能够节省多少内存?记忆总是那么脆弱, ...
最新文章
- 无线网***工具进攻方法及防范技巧
- 用Memcache守护程序把数据缓存到内存二
- 了解CUDA计算(一)
- (chap1 网络基础知识)网络的构成要素:(4-6)集线器和3层交换机
- 2.4.2 死锁的处理策略-预防死锁
- mysql 安装 菜鸟_mysql安装
- VTK:相互作用之RubberBand2DObserver
- SQL with(unlock)与with(readpast) (转)
- 【转贴】pentaho4.5汉化攻略及汉化文件
- java常用类介绍及源码阅读(LinkedList)
- 【转载】SQL Server 批量插入数据的两种方法
- 领导让我重写测试代码,我该怎么办?
- 利用辗转相除法求两个数的最大公约数
- Atitit Mysql查询优化器 存取类型 范围存取类型 索引存取类型 AND or的分析
- 常见linux服务器存储空间,全面了解linux服务器的常用命令总结
- 设计模式-4.行为型模式(模板方法模式/策略模式/命令模式/职责链模式/状态模式/观察者模式/中介者模式/迭代器模式/访问者模式/备忘录模式/解释器模式)
- 欧陆词典导入词典库(自定义英文词典)
- 学计算机网络布线图片,从业必看!直观的弱电各子系统图!
- 打印机后台程序没有运行怎么办
- 领英linkedin使用手册—领英好友人脉搜索方式方法