轻松理解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编写简单的微博爬虫
Mar 04 Python
python复制文件到指定目录的实例
Apr 27 Python
Python小工具之消耗系统指定大小内存的方法
Dec 03 Python
Mac 使用python3的matplot画图不显示的解决
Nov 23 Python
Python数据可视化:顶级绘图库plotly详解
Dec 07 Python
Python集合操作方法详解
Feb 09 Python
django 读取图片到页面实例
Mar 27 Python
Python itertools.product方法代码实例
Mar 27 Python
Python发送邮件实现基础解析
Aug 14 Python
套娃式文件夹如何通过Python批量处理
Aug 23 Python
Python大批量搜索引擎图像爬虫工具详解
Nov 16 Python
scrapy实践之翻页爬取的实现
Jan 05 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解析url并得到url参数方法总结
2018/10/11 PHP
laravel批量生成假数据的方法
2019/10/09 PHP
Javascript学习笔记8 用JSON做原型
2010/01/11 Javascript
基于jQuery的弹出警告对话框美化插件(警告,确认和提示)
2010/06/10 Javascript
JS代码放在head和body中的区别分析
2011/12/01 Javascript
javascript 在firebug调试时用console.log的方法
2012/05/10 Javascript
原生js实现图片层叠轮播切换效果
2016/02/02 Javascript
javascript HTML5 Canvas实现圆盘抽奖功能
2016/04/11 Javascript
JS事件添加和移出的兼容写法示例
2016/06/20 Javascript
JS正则表达式学习之贪婪和非贪婪模式实例总结
2016/12/26 Javascript
详解angularjs的数组传参方式的简单实现
2017/07/28 Javascript
angular5 子组件监听父组件传入值的变化方法
2018/09/30 Javascript
微信小程序BindTap快速连续点击目标页面跳转多次问题处理
2019/04/08 Javascript
vue组件之间的数据传递方法详解
2019/04/19 Javascript
解决layui弹框失效的问题
2019/09/09 Javascript
vue中进行微博分享的实例讲解
2019/10/14 Javascript
Vue axios 将传递的json数据转为form data的例子
2019/10/29 Javascript
python实现文本文件合并
2015/12/29 Python
Python多线程扫描端口代码示例
2018/02/09 Python
Python实现正则表达式匹配任意的邮箱方法
2018/12/20 Python
Python和Go语言的区别总结
2019/02/20 Python
python GUI库图形界面开发之PyQt5菜单栏控件QMenuBar的详细使用方法与实例
2020/02/28 Python
CSS3中使用RGBa来调节透明度的教程
2016/05/09 HTML / CSS
以实惠的价格轻松租车,免费取消:Easyrentcars
2019/07/16 全球购物
世界各地的当地人的食物体验:Eatwith
2019/07/26 全球购物
乐高瑞士官方商店:LEGO CH
2020/08/16 全球购物
Linux操作面试题
2015/02/11 面试题
办公室文员工作自我评价
2013/12/01 职场文书
初一生物教学反思
2014/01/18 职场文书
《美丽的彩虹》教学反思
2014/02/25 职场文书
三字经教学反思
2014/04/26 职场文书
倡议书格式模板
2014/05/13 职场文书
大学生翘课检讨书范文
2014/10/06 职场文书
交通运输局四风问题对照检查材料思想汇报
2014/10/09 职场文书
利用前端HTML+CSS+JS开发简单的TODOLIST功能(记事本)
2021/04/13 Javascript
通过feDisplacementMap和feImage实现水波特效
2022/04/24 HTML / CSS