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 multiprocessing.Manager介绍和实例(进程间共享数据)
Nov 21 Python
python开发之thread实现布朗运动的方法
Nov 11 Python
Python实现约瑟夫环问题的方法
May 03 Python
使用Python读取大文件的方法
Feb 11 Python
儿童python练习实例
May 27 Python
win10系统下Anaconda3安装配置方法图文教程
Sep 19 Python
使用python判断你是青少年还是老年人
Nov 29 Python
Python函数参数匹配模型通用规则keyword-only参数详解
Jun 10 Python
python matplotlib如何给图中的点加标签
Nov 14 Python
Pycharm IDE的安装和使用教程详解
Apr 30 Python
Python爬虫入门教程01之爬取豆瓣Top电影
Jan 24 Python
Python机器学习应用之工业蒸汽数据分析篇详解
Jan 18 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
最省空间的计数器
2006/10/09 PHP
PHP中的类型提示(type hinting)功能介绍
2015/07/01 PHP
PHP使用观察者模式处理异常信息的方法详解
2019/09/24 PHP
JavaScript 三种创建对象的方法
2009/10/16 Javascript
web页面数据展示新想法(json)
2010/06/08 Javascript
jquery isType() 类型判断代码
2011/02/14 Javascript
jQuery的学习步骤
2011/02/23 Javascript
js中if语句的几种优化代码写法
2011/03/12 Javascript
js触发asp.net的Button的Onclick事件应用
2013/02/02 Javascript
jquery操作select取值赋值与设置选中实例
2017/02/28 Javascript
jQuery EasyUI之验证框validatebox实例详解
2017/04/10 jQuery
webpack-dev-server远程访问配置方法
2018/02/22 Javascript
解决vue多个路由共用一个页面的问题
2018/03/12 Javascript
vue拖拽组件使用方法详解
2018/12/01 Javascript
Vue+ElementUI项目使用webpack输出MPA的方法
2019/08/27 Javascript
angular inputNumber指令输入框只能输入数字的实现
2019/12/03 Javascript
JS数组方法push()、pop()用法实例分析
2020/01/18 Javascript
vue项目在线上服务器访问失败原因分析
2020/08/14 Javascript
为什么JavaScript中0.1 + 0.2 != 0.3
2020/12/03 Javascript
[01:13]这,就是刀塔
2014/07/16 DOTA
[52:00]2018DOTA2亚洲邀请赛 4.1 小组赛 A组加赛 LGD vs Optic
2018/04/02 DOTA
Python3实现发送QQ邮件功能(html)
2017/12/15 Python
python中的闭包函数
2018/02/09 Python
selenium+python自动化测试之环境搭建
2019/01/23 Python
python 微信好友特征数据分析及可视化
2020/01/07 Python
Python列表解析操作实例总结
2020/02/26 Python
python GUI库图形界面开发之PyQt5菜单栏控件QMenuBar的详细使用方法与实例
2020/02/28 Python
快速解决pymongo操作mongodb的时区问题
2020/12/05 Python
美国领先的家居装饰和礼品商店:Kirkland’s
2017/01/30 全球购物
酒吧创业计划书
2014/01/18 职场文书
横空出世观后感
2015/06/09 职场文书
关于法制教育的宣传语
2015/07/13 职场文书
发言稿之优秀教师篇
2019/09/26 职场文书
tensorflow学习笔记之tfrecord文件的生成与读取
2021/03/31 Python
Redisson实现Redis分布式锁的几种方式
2021/08/07 Redis
js中Map和Set的用法及区别实例详解
2022/02/15 Javascript