轻松理解Python 中的 descriptor


Posted in Python onSeptember 15, 2017

定义

通常,一个 descriptor 是具有“绑定行为”的对象属性。所绑定行为可通过 descriptor 协议被自定义的 __get__() , __set__() 和 __delete__() 方法重写。如果一个对象的上述三个方法任意一个被重写,则就可被称为 descriptor。

属性的默认操作是从对象字典中获取、设置和删除一个属性。例如,a.x 有一个查找链,先 a.__dict__['x'] ,若没有则 type(a).__dict__['x'] ,若没有增往上查找父类直到元类。如果查找链中,对象被定义了 descriptor 方法,Python 就会覆盖默认行为。

Descriptor 是一个强大的工具,虽然开发者不常接触到它,但它其实就是类、属性、函数、方法、静态方法、类方法以及 super() 背后的运行机制。

Descriptor 协议

三个方法原型如下所示:

descr.__get__(self, obj, type=None) --> value
descr.__set__(self, obj, value) --> None
descr.__delete__(self, obj) --> None

数据 descriptor 是同时具有 __get__() 和 __set__() 方法的对象,若只有 __get__() 方法,则为非数据 descriptor。如果实例字典中有和数据 descriptor 同名的入口,则数据 descriptor 优先级更高。相反,非数据 descriptor 优先级低。

让 __set__() 方法抛出异常,就能创建一个只读数据 descriptor。

调用 descriptor

descriptor 可以直接通过方法名调用。例如, d.__get__(obj) 。

而通过访问对象属性,自动调用 descriptor 才是更通用的做法。例如,如果 d 定义了方法 __get__() ,则 obj.d 会调用 d.__get__(obj) 。

对于对象, b.x 会被转换成 type(b).__dict__['x'].__get__(b, type(b)) 。而对于类(是的,类也可以调用), B.x 会被转换成 B.__dict__['x'].__get__(None, B) 。

Descriptor 例子

class RevealAccess(object):
  """A data descriptor that sets and returns values
    normally and prints a message logging their access.
  """
  def __init__(self, initval=None, name='var'):
    self.val = initval
    self.name = name
  def __get__(self, obj, objtype):
    print('Retrieving', self.name)
    return self.val
  def __set__(self, obj, val):
    print('Updating', self.name)
    self.val = val
>>> class MyClass(object):
...   x = RevealAccess(10, 'var "x"')
...   y = 5
...
>>> m = MyClass()
>>> m.x
Retrieving var "x"
10
>>> m.x = 20
Updating var "x"
>>> m.x
Retrieving var "x"
20
>>> m.y
5

总结

以上所述是小编给大家介绍的Python 中的 descriptor,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Python 相关文章推荐
Python和JavaScript间代码转换的4个工具
Feb 22 Python
web.py 十分钟创建简易博客实现代码
Apr 22 Python
WINDOWS 同时安装 python2 python3 后 pip 错误的解决方法
Mar 16 Python
python使用mysql数据库示例代码
May 21 Python
Python模块搜索路径代码详解
Jan 29 Python
深入理解Python中的 __new__ 和 __init__及区别介绍
Sep 17 Python
对python3标准库httpclient的使用详解
Dec 18 Python
从0开始的Python学习014面向对象编程(推荐)
Apr 02 Python
django 多对多表的创建和插入代码实现
Sep 09 Python
Python如何获取文件指定行的内容
May 27 Python
PIL.Image.open和cv2.imread的比较与相互转换的方法
Jun 03 Python
用python获取txt文件中关键字的数量
Dec 24 Python
Python 实现购物商城,含有用户入口和商家入口的示例
Sep 15 #Python
python中reload(module)的用法示例详解
Sep 15 #Python
Python 关于反射和类的特殊成员方法
Sep 14 #Python
在Python中执行系统命令的方法示例详解
Sep 14 #Python
关于Python如何避免循环导入问题详解
Sep 14 #Python
Python实现随机选择元素功能
Sep 14 #Python
python自动化脚本安装指定版本python环境详解
Sep 14 #Python
You might like
PHP队列用法实例
2014/11/05 PHP
使用Codeigniter重写insert的方法(推荐)
2017/03/23 PHP
PHP基于SMTP协议实现邮件发送实例代码
2017/04/27 PHP
PHP使用pdo连接access数据库并循环显示数据操作示例
2018/06/05 PHP
JS下拉缓冲菜单示例代码
2013/08/30 Javascript
javascript静态页面传值的三种方法分享
2013/11/12 Javascript
javascript实现简单的页面右下角提示信息框
2015/07/31 Javascript
JavaScript实现可拖拽的拖动层Div实例
2015/08/05 Javascript
jquery实现动画菜单的左右滚动、渐变及图形背景滚动等效果
2015/08/25 Javascript
AngularJS 2.0新特性有哪些
2016/02/18 Javascript
分享JS数组求和与求最大值的方法
2016/08/11 Javascript
利用JS实现文字的聚合动画效果
2017/01/22 Javascript
jQuery实现frame之间互通的方法
2017/06/26 jQuery
详解基于node的前端项目编译时内存溢出问题
2017/08/01 Javascript
javascript 取小数点后几位几种方法总结
2017/08/02 Javascript
vue中Element-ui 输入银行账号每四位加一个空格的实现代码
2018/09/14 Javascript
vue实现弹框遮罩点击其他区域弹框关闭及v-if与v-show的区别介绍
2018/09/29 Javascript
koa大型web项目中使用路由装饰器的方法示例
2019/04/02 Javascript
js实现课堂随机点名系统
2019/11/21 Javascript
[02:17]《辉夜杯》TRG战队巡礼
2015/10/26 DOTA
Python函数学习笔记
2008/10/07 Python
python使用内存zipfile对象在内存中打包文件示例
2014/04/30 Python
python连接oracle数据库实例
2014/10/17 Python
Python实现的字典值比较功能示例
2018/01/08 Python
详解Python学习之安装pandas
2019/04/16 Python
Python API 操作Hadoop hdfs详解
2020/06/06 Python
html5弹跳球示例代码
2013/07/23 HTML / CSS
英国泰坦旅游网站:全球陪同游览,邮轮和铁路旅行
2016/11/29 全球购物
台湾7-ELEVEN线上购物中心:7-11
2021/01/21 全球购物
网上开店必备创业计划书
2014/01/26 职场文书
会计岗位描述
2014/02/22 职场文书
消防安全标语
2014/06/07 职场文书
政风行风评议心得体会
2014/10/21 职场文书
求职信范文怎么写
2015/03/19 职场文书
项目经理助理岗位职责
2015/04/13 职场文书