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中lambda函数 list comprehension 和 zip函数使用指南
Sep 28 Python
Django中模型Model添加JSON类型字段的方法
Jun 17 Python
Python生成随机验证码的两种方法
Dec 22 Python
python 计算文件的md5值实例
Jan 13 Python
Python中模块与包有相同名字的处理方法
May 05 Python
python模块smtplib学习
May 22 Python
Python实现操纵控制windows注册表的方法分析
May 24 Python
python GUI库图形界面开发之PyQt5信号与槽多窗口数据传递详细使用方法与实例
Mar 08 Python
python数据库开发之MongoDB安装及Python3操作MongoDB数据库详细方法与实例
Mar 18 Python
pandas DataFrame 数据选取,修改,切片的实现
Apr 24 Python
打印tensorflow恢复模型中所有变量与操作节点方式
May 26 Python
python树莓派通过队列实现进程交互的程序分析
Jul 04 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 error_log 函数的使用
2009/04/13 PHP
PHP 字符串 小常识
2009/06/05 PHP
phpExcel导出大量数据出现内存溢出错误的解决方法
2013/02/28 PHP
php如何比较两个浮点数是否相等详解
2019/02/12 PHP
用JavaScript对JSON进行模式匹配(Part 1-设计)
2010/07/17 Javascript
javascript中的delete使用详解
2013/04/11 Javascript
jquery中ajax函数执行顺序问题之如何设置同步
2014/02/28 Javascript
php实例分享之实现显示网站运行时间
2014/05/20 Javascript
让IE8浏览器支持function.bind()方法
2014/10/16 Javascript
jQuery过滤选择器详解
2015/01/13 Javascript
JS实现跟随鼠标立体翻转图片的方法
2015/05/04 Javascript
浅谈Javascript中substr和substring的区别
2015/09/30 Javascript
javascript合并表格单元格实例代码
2016/01/03 Javascript
利用Angular.js限制textarea输入的字数
2016/10/20 Javascript
基于JS实现横线提示输入验证码随验证码输入消失(js验证码的实现)
2016/10/27 Javascript
vue2中filter()的实现代码
2017/07/09 Javascript
使用nvm和nrm优化node.js工作流的方法
2019/01/17 Javascript
AjaxFileUpload.js实现异步上传文件功能
2019/04/19 Javascript
node解析修改nginx配置文件操作实例分析
2019/11/06 Javascript
vue项目接口管理,所有接口都在apis文件夹中统一管理操作
2020/08/13 Javascript
JavaScript/TypeScript 实现并发请求控制的示例代码
2021/01/18 Javascript
Python查找两个有序列表中位数的方法【基于归并算法】
2018/04/20 Python
Python使用Pickle模块进行数据保存和读取的讲解
2019/04/09 Python
python自动化unittest yaml使用过程解析
2020/02/03 Python
python基本算法之实现归并排序(Merge sort)
2020/09/01 Python
python安装及变量名介绍详解
2020/12/12 Python
详解如何通过H5(浏览器/WebView/其他)唤起本地app
2017/12/11 HTML / CSS
应届生.NET方向面试题
2015/05/23 面试题
英语专业毕业生自荐信
2013/10/28 职场文书
音乐专业应届生教师求职信
2013/11/04 职场文书
优秀老师事迹材料
2014/02/05 职场文书
《木笛》教学反思
2014/03/01 职场文书
观看信仰心得体会
2014/09/04 职场文书
通知书大全
2015/04/27 职场文书
小学数学继续教育研修日志
2015/11/13 职场文书
Windows10安装Apache2.4的方法步骤
2022/06/25 Servers