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的Flask框架中web表单的教程
Apr 20 Python
python使用arcpy.mapping模块批量出图
Mar 06 Python
浅谈Python黑帽子取代netcat
Feb 10 Python
Python实现中一次读取多个值的方法
Apr 22 Python
Python3删除排序数组中重复项的方法分析
Jan 31 Python
利用python、tensorflow、opencv、pyqt5实现人脸实时签到系统
Sep 25 Python
Django对接支付宝实现支付宝充值金币功能示例
Dec 17 Python
Python实现从N个数中找到最大的K个数
Apr 02 Python
浅谈opencv自动光学检测、目标分割和检测(连通区域和findContours)
Jun 04 Python
浅析Python 字符编码与文件处理
Sep 24 Python
完美解决Pycharm中matplotlib画图中文乱码问题
Jan 11 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
php实现的遍历文件夹下所有文件,编辑删除
2010/01/05 PHP
PHP 伪静态技术原理以及突破原理实现介绍
2013/07/12 PHP
解决form中action属性后面?传递参数 获取不到的问题
2017/07/21 PHP
阿里云Win2016安装Apache和PHP环境图文教程
2018/03/11 PHP
从sohu弄下来的flash中展示图片的代码
2007/04/27 Javascript
javascript或asp实现的判断身份证号码是否正确两种验证方法
2009/11/26 Javascript
jQuery Ajax 实例全解析
2011/04/20 Javascript
更优雅的事件触发兼容
2011/10/24 Javascript
jquery实现pager控件示例
2014/04/09 Javascript
利用a标签自动解析URL分析网址实例
2014/10/20 Javascript
jQuery简单tab切换效果实现方法
2015/04/08 Javascript
js正则表达式replace替换变量方法
2016/05/21 Javascript
Jquery UI实现一次拖拽多个选中的元素操作
2020/12/01 Javascript
Vue组件开发之LeanCloud带图形校验码的短信发送功能
2017/11/07 Javascript
vue webpack打包优化操作技巧
2018/02/22 Javascript
webpack4简单入门实例
2018/09/06 Javascript
vue基础之事件简写、事件对象、冒泡、默认行为、键盘事件实例分析
2019/03/11 Javascript
vue router 用户登陆功能的实例代码
2019/04/24 Javascript
关于引入vue.js 文件的知识点总结
2020/01/28 Javascript
Python中装饰器兼容加括号和不加括号的写法详解
2017/07/05 Python
Python读取mat文件,并转为csv文件的实例
2018/07/04 Python
Python获取航线信息并且制作成图的讲解
2019/01/03 Python
如何基于python实现归一化处理
2020/01/20 Python
使用Html5中的cavas画一面国旗
2019/09/25 HTML / CSS
Joe Fresh官网:加拿大时尚品牌和零售连锁店
2016/11/30 全球购物
澳洲的服装老品牌:SABA
2018/02/06 全球购物
100%植物性、有机、即食餐:Sakara Life
2018/10/25 全球购物
Wiggle澳大利亚:自行车、跑步、游泳商店
2020/11/07 全球购物
如何写出高性能的JSP和Servlet
2013/01/22 面试题
员工晚婚的请假条
2014/02/08 职场文书
房屋转让协议书
2014/04/11 职场文书
困难补助申请报告
2015/05/19 职场文书
2015年政府采购工作总结
2015/05/21 职场文书
元旦晚会开场白
2015/05/29 职场文书
导游词之神仙居景区
2019/11/15 职场文书
使用ORM新增数据在Mysql中的操作步骤
2021/07/26 MySQL