Python中的descriptor描述器简明使用指南


Posted in Python onJune 02, 2016

当定义迭代器的时候,描述是实现迭代协议的对象,即实现__iter__方法的对象。同理,所谓描述器,即实现了描述符协议,即__get__, __set__, 和 __delete__方法的对象。

单看定义,还是比较抽象的。talk is cheap。看代码吧:

class WebFramework(object):
  def __init__(self, name='Flask'):
    self.name = name

  def __get__(self, instance, owner):
    return self.name

  def __set__(self, instance, value):
    self.name = value


class PythonSite(object):

  webframework = WebFramework()

In [1]: PythonSite.webframework
Out[1]: 'Flask'

In [2]: PythonSite.webframework = 'Tornado'

In [3]: PythonSite.webframework
Out[3]: 'Tornado'

定义了一个类WebFramework,它实现了描述符协议__get__和__set__,该对象(类也是对象,一切都是对象)即成为了一个描述器。同时实现__get__和__set__的称之为资料描述器(data descriptor)。仅仅实现__get__的则为非描述器。两者的差别是相对于实例的字典的优先级。

如果实例字典中有与描述器同名的属性,如果描述器是资料描述器,优先使用资料描述器,如果是非资料描述器,优先使用字典中的属性。

描述器的调用
对于这类魔法,其调用方法往往不是直接使用的。例如装饰器需要用 @ 符号调用。迭代器通常在迭代过程,或者使用 next 方法调用。描述器则比较简单,对象属性的时候会调用。

In [15]: webframework = WebFramework()

In [16]: webframework.__get__(webframework, WebFramework)
Out[16]: 'Flask'

描述器的应用
描述器的作用主要在方法和属性的定义上。既然我们可以重新描述类的属性,那么这个魔法就可以改变类的一些行为。最简单的应用则是可以配合装饰器,写一个类属性的缓存。Flask的作者写了一个werkzeug网络工具库,里面就使用描述器的特性,实现了一个缓存器。

class _Missing(object):
  def __repr__(self):
    return 'no value'

  def __reduce__(self):
    return '_missing'


_missing = _Missing()


class cached_property(object):
  def __init__(self, func, name=None, doc=None):
    self.__name__ = name or func.__name__
    self.__module__ = func.__module__
    self.__doc__ = doc or func.__doc__
    self.func = func

  def __get__(self, obj, type=None):
    if obj is None:
      return self
    value = obj.__dict__.get(self.__name__, _missing)
    if value is _missing:
      value = self.func(obj)
      obj.__dict__[self.__name__] = value
    return value


class Foo(object):
  @cached_property
  def foo(self):
    print 'first calculate'
    result = 'this is result'
    return result


f = Foo()

print f.foo  # first calculate this is result
print f.foo  # this is result

运行结果可见,first calculate只在第一次调用时候被计算之后就把结果缓存起来了。这样的好处是在网络编程中,对HTTP协议的解析,通常会把HTTP的header解析成python的一个字典,而在视图函数的时候,可能不知一次的访问这个header,因此把这个header使用描述器缓存起来,可以减少多余的解析。

描述器在python的应用十分广泛,通常是配合装饰器一起使用。强大的魔法来自强大的责任。描述器还可以用来实现ORM中对sql语句的"预编译"。恰当的使用描述器,可以让自己的Python代码更优雅。

Python 相关文章推荐
python标准日志模块logging的使用方法
Nov 01 Python
python计算圆周长、面积、球体体积并画出圆
Apr 08 Python
python中合并两个文本文件并按照姓名首字母排序的例子
Apr 25 Python
django+xadmin+djcelery实现后台管理定时任务
Aug 14 Python
python3爬虫学习之数据存储txt的案例详解
Apr 24 Python
使用python的turtle绘画滑稽脸实例
Nov 21 Python
JupyterNotebook 输出窗口的显示效果调整方法
Apr 13 Python
利用4行Python代码监测每一行程序的运行时间和空间消耗
Apr 22 Python
Python3.8.2安装包及安装教程图文详解(附安装包)
Nov 28 Python
Python爬虫之Selenium库的使用方法
Jan 03 Python
Linux系统下升级pip的完整步骤
Jan 31 Python
Python面向对象之内置函数相关知识总结
Jun 24 Python
Python黑魔法Descriptor描述符的实例解析
Jun 02 #Python
深入理解Python变量与常量
Jun 02 #Python
Python中的Descriptor描述符学习教程
Jun 02 #Python
从源码解析Python的Flask框架中request对象的用法
Jun 02 #Python
Python搭建APNS苹果推送通知推送服务的相关模块使用指南
Jun 02 #Python
Python的Django框架中使用SQLAlchemy操作数据库的教程
Jun 02 #Python
实例解析Python中的__new__特殊方法
Jun 02 #Python
You might like
《OVERLORD》第四季,终于等到你!
2020/03/02 日漫
PHP数组传递是值传递而非引用传递概念纠正
2013/01/31 PHP
php使用ICQ网关发送手机短信
2013/10/30 PHP
php实现可以设置中奖概率的抽奖程序代码分享
2014/01/19 PHP
php 三元运算符实例详细介绍
2016/12/15 PHP
jquery简单体验
2007/01/10 Javascript
ExtJs3.0中Store添加 baseParams 的Bug
2010/03/10 Javascript
js常用代码段收集
2011/10/28 Javascript
JS 屏蔽键盘不可用与鼠标右键不可用的方法
2013/11/18 Javascript
优化Node.js Web应用运行速度的10个技巧
2014/09/03 Javascript
jQuery中hide()方法用法实例
2014/12/24 Javascript
解析Node.js基于模块和包的代码部署方式
2016/02/16 Javascript
jQuery实现鼠标跟随提示层效果代码(可显示文本,Div,Table,Html等)
2016/04/18 Javascript
jQuery选择器及jquery案例详解(必看)
2016/05/20 Javascript
jQuery获取浏览器类型和版本号的方法
2016/07/05 Javascript
全面解析Bootstrap表单样式的使用
2016/09/09 Javascript
微信小程序开发实战教程之手势解锁
2016/11/18 Javascript
js eval函数使用,js对象和字符串互转实例
2017/03/06 Javascript
vue轮播图插件vue-awesome-swiper的使用代码实例
2017/07/10 Javascript
使用JQ完成表格隔行换色的简单实例
2017/08/25 Javascript
从0到1构建vueSSR项目之node以及vue-cli3的配置
2019/03/07 Javascript
JQuery事件委托原理与用法实例分析
2019/05/13 jQuery
javascript实现切割轮播效果
2019/11/28 Javascript
[02:41]DOTA2亚洲邀请赛小组赛第三日 赛事回顾
2015/02/01 DOTA
使用Tensorflow实现可视化中间层和卷积层
2020/01/24 Python
python多进程使用函数封装实例
2020/05/02 Python
PyCharm Community安装与配置的详细教程
2020/11/24 Python
世界首屈一指的在线男士内衣权威:HisRoom
2017/08/05 全球购物
保险公司晨会主持词
2014/03/22 职场文书
党校个人自我鉴定范文
2014/03/28 职场文书
村官个人总结范文
2015/03/03 职场文书
客服专员岗位职责范本
2015/04/07 职场文书
诉讼和解协议书
2016/03/23 职场文书
OpenCV绘制圆端矩形的示例代码
2021/08/30 Python
Python卷积神经网络图片分类框架详解分析
2021/11/07 Python
Win11远程连接不上怎么办?Win11远程桌面用不了的解决方法
2022/08/05 数码科技