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连接MySQL数据库实例分析
May 12 Python
使用PyCharm配合部署Python的Django框架的配置纪实
Nov 19 Python
python生成验证码图片代码分享
Jan 28 Python
Python中property属性实例解析
Feb 10 Python
Python中将变量按行写入txt文本中的方法
Apr 03 Python
Python使用try except处理程序异常的三种常用方法分析
Sep 05 Python
python实现自动登录
Sep 17 Python
python中的tcp示例详解
Dec 09 Python
修改python plot折线图的坐标轴刻度方法
Dec 13 Python
Python两个字典键同值相加的几种方法
Mar 05 Python
使用python远程操作linux过程解析
Dec 04 Python
python输出pdf文档的实例
Feb 13 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
php编写一个简单的路由类
2011/04/13 PHP
Destoon实现多表查询示例
2014/08/21 PHP
php返回当前日期或者指定日期是周几
2015/05/21 PHP
PHP接收json 并将接收数据插入数据库的实现代码
2015/12/01 PHP
浅谈Laravel核心解读之Console内核
2018/12/02 PHP
showModalDialog 和 showModelessDialog
2007/01/22 Javascript
jquery validate使用攻略 第四步
2010/07/01 Javascript
jquery下异步提交表单 异步跨域提交表单
2010/11/17 Javascript
JS获取键盘上任意按键的值(实例代码)
2013/11/12 Javascript
深入讲解AngularJS中的自定义指令的使用
2015/06/18 Javascript
以Python代码实例展示kNN算法的实际运用
2015/10/26 Javascript
JavaScript预解析及相关技巧分析
2016/04/21 Javascript
Angular ng-class详解及实例代码
2016/09/19 Javascript
Javascript基于jQuery UI实现选中区域拖拽效果
2016/11/25 Javascript
vue2.0构建单页应用最佳实战
2017/04/01 Javascript
微信小程序 图片宽高自适应详解
2017/05/11 Javascript
JavaScript异步加载问题总结
2018/02/17 Javascript
js实现验证码功能
2020/07/24 Javascript
前端性能优化建议
2020/09/17 Javascript
vue添加自定义右键菜单的完整实例
2020/12/08 Vue.js
js闭包和垃圾回收机制示例详解
2021/03/01 Javascript
[53:23]Secret vs Liquid 2018国际邀请赛淘汰赛BO3 第二场 8.25
2018/08/29 DOTA
Pthon批量处理将pdb文件生成dssp文件
2015/06/21 Python
Python基于递归算法实现的走迷宫问题
2017/08/04 Python
对Python 网络设备巡检脚本的实例讲解
2018/04/22 Python
Django数据库类库MySQLdb使用详解
2019/04/28 Python
对python中不同模块(函数、类、变量)的调用详解
2019/07/16 Python
Myholidays美国:在线旅游网站
2019/08/16 全球购物
结婚邀请函范文
2014/01/14 职场文书
会计专业应届生自荐信
2014/02/07 职场文书
cf搞笑广告词
2014/03/14 职场文书
古汉语文学求职信范文
2014/03/16 职场文书
写给领导的感谢信
2015/01/22 职场文书
学习保证书100字
2015/02/26 职场文书
2015年教学副校长工作总结
2015/07/22 职场文书
《陶罐和铁罐》教学反思
2016/03/03 职场文书