轻松理解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模拟新浪微博登陆功能(新浪微博爬虫)
Dec 24 Python
Python3基础之输入和输出实例分析
Aug 18 Python
在Linux上安装Python的Flask框架和创建第一个app实例的教程
Mar 30 Python
Python实现树的先序、中序、后序排序算法示例
Jun 23 Python
python中Matplotlib实现绘制3D图的示例代码
Sep 04 Python
通过pykafka接收Kafka消息队列的方法
Dec 27 Python
解决pycharm下os.system执行命令返回有中文乱码的问题
Jul 07 Python
Win10系统下安装labelme及json文件批量转化方法
Jul 30 Python
python 实现任务管理清单案例
Apr 25 Python
python函数调用,循环,列表复制实例
May 03 Python
python实现扫雷游戏的示例
Oct 20 Python
python温度转换华氏温度实现代码
Dec 06 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增删改查示例自己写的demo
2013/09/04 PHP
php实现的debug log日志操作类实例
2016/07/12 PHP
浅谈ThinkPHP5.0版本和ThinkPHP3.2版本的区别
2017/06/17 PHP
Laravel 5.4因特殊字段太长导致migrations报错的解决
2017/10/22 PHP
Laravel框架Eloquent ORM删除数据操作示例
2019/12/03 PHP
文字幻灯片
2006/06/26 Javascript
javascript多种数据类型表格排序代码分析
2010/09/11 Javascript
基于jquery实现状态限定编辑的代码
2012/02/11 Javascript
javascript 原型链维护和继承详解
2014/11/26 Javascript
js制作简易年历完整实例
2015/01/28 Javascript
纯javascript判断查询日期是否为有效日期
2015/08/24 Javascript
AngularJS延迟加载html template
2016/07/27 Javascript
Mongoose实现虚拟字段查询的方法详解
2017/08/15 Javascript
基于JavaScript实现带数据验证和复选框的表单提交
2017/08/23 Javascript
关于vue-router的那些事儿
2018/05/23 Javascript
Vue.js实现的计算器功能完整示例
2018/07/11 Javascript
JS在if中的强制类型转换方式
2018/07/15 Javascript
JavaScript学习笔记之DOM基础操作实例小结
2019/01/09 Javascript
JavaScript刷新页面的几种方法总结
2019/03/28 Javascript
python列表去重的二种方法
2014/02/14 Python
python中常用检测字符串相关函数汇总
2015/04/15 Python
python去除字符串中的换行符
2017/10/11 Python
python提取具有某种特定字符串的行数据方法
2018/12/11 Python
Python中调用其他程序的方式详解
2019/08/06 Python
如何使用Python抓取网页tag操作
2020/02/14 Python
python3:excel操作之读取数据并返回字典 + 写入的案例
2020/09/01 Python
总结python 三种常见的内存泄漏场景
2020/11/20 Python
戴尔加拿大官网:Dell加拿大
2016/09/17 全球购物
小学生十佳少年事迹材料
2014/08/20 职场文书
一年级班主任工作总结2014
2014/11/08 职场文书
2015年员工试用期工作总结
2014/12/12 职场文书
幼儿园安全管理制度
2015/08/05 职场文书
2015年社区消防安全工作总结
2015/10/14 职场文书
小学秋季运动会通讯稿
2015/11/25 职场文书
《风娃娃》教学反思
2016/02/18 职场文书
分享几个JavaScript运算符的使用技巧
2021/04/24 Javascript