轻松理解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 23 Python
Python随机生成彩票号码的方法
Mar 05 Python
Python探索之爬取电商售卖信息代码示例
Oct 27 Python
Python中垃圾回收和del语句详解
Nov 15 Python
微信小程序python用户认证的实现
Jul 29 Python
python实现复制文件到指定目录
Oct 16 Python
Python绘制三角函数图(sin\cos\tan)并标注特定范围的例子
Dec 04 Python
python django中8000端口被占用的解决
Dec 17 Python
Python range与enumerate函数区别解析
Feb 28 Python
Python matplotlib实时画图案例
Apr 23 Python
Python 3.10 的首个 PEP 诞生,内置类型 zip() 迎来新特性(推荐)
Jul 03 Python
浅析Python的命名空间与作用域
Nov 25 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的反射机制实例详解
2017/03/29 PHP
Extjs Ext.MessageBox.confirm 确认对话框详解
2010/04/02 Javascript
jQuery参数列表集合
2011/04/06 Javascript
利用JS来控制键盘的上下左右键(示例代码)
2013/12/14 Javascript
jQuery截取指定长度字符串代码
2014/08/21 Javascript
jquery实现增加删除行的方法
2015/02/03 Javascript
关于Angular2 + node接口调试的解决方案
2017/05/28 Javascript
Angular.js中window.onload(),$(document).ready()的写法浅析
2017/09/28 Javascript
js实现随机点名系统(实例讲解)
2017/10/18 Javascript
VUEJS 2.0 子组件访问/调用父组件的实例
2018/02/10 Javascript
Vue动态修改网页标题的方法及遇到问题
2019/06/09 Javascript
解决Vue动态加载本地图片问题
2019/10/09 Javascript
jQuery+ajax实现用户登录验证
2020/09/13 jQuery
Vue+axios封装请求实现前后端分离
2020/10/23 Javascript
Antd-vue Table组件添加Click事件,实现点击某行数据教程
2020/11/17 Javascript
[04:10]2016国际邀请赛中国区预选赛第二日TOP10精彩集锦
2016/06/28 DOTA
Python基于Pymssql模块实现连接SQL Server数据库的方法详解
2017/07/20 Python
Flask框架响应、调度方法和蓝图操作实例分析
2018/07/24 Python
Python-ElasticSearch搜索查询的讲解
2019/02/25 Python
Python PO设计模式的具体使用
2019/08/16 Python
Python3 文章标题关键字提取的例子
2019/08/26 Python
django框架两个使用模板实例
2019/12/11 Python
python中return的返回和执行实例
2019/12/24 Python
Python Selenium模块安装使用教程详解
2020/07/09 Python
Roots加拿大官网:加拿大休闲服饰品牌
2016/10/24 全球购物
中国最大隐形眼镜网上商城:视客眼镜网
2016/10/30 全球购物
印尼最大的婴儿用品购物网站:Orami
2017/09/28 全球购物
美国班级戒指、帽子和礼服、毕业产品、年鉴:Balfour
2018/11/01 全球购物
C#实现启动一个进程
2016/10/01 面试题
高中自我鉴定
2013/12/20 职场文书
经典英文广告词
2014/03/18 职场文书
学习十八大演讲稿
2014/09/15 职场文书
2014客服代表实习自我鉴定
2014/09/18 职场文书
故宫导游词
2015/01/31 职场文书
党小组鉴定意见
2015/06/02 职场文书
学校安全管理制度
2015/08/06 职场文书