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字符串连接的N种方式总结
Sep 17 Python
在Python下尝试多线程编程
Apr 28 Python
Python实现将xml导入至excel
Nov 20 Python
Python中的groupby分组功能的实例代码
Jul 11 Python
对pandas写入读取h5文件的方法详解
Dec 28 Python
pandas删除指定行详解
Apr 04 Python
python交互模式下输入换行/输入多行命令的方法
Jul 02 Python
pandas DataFrame创建方法的方式
Aug 02 Python
Pytorch数据拼接与拆分操作实现图解
Apr 30 Python
解决导入django_filters不成功问题No module named 'django_filter'
Jul 15 Python
改变 Python 中线程执行顺序的方法
Sep 24 Python
解决pycharm导入numpy包的和使用时报错:RuntimeError: The current Numpy installation (‘D:\\python3.6\\lib\\site-packa的问题
Dec 08 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往windows中添加用户
2006/12/06 PHP
初步介绍PHP扩展开发经验分享
2012/09/06 PHP
PHP魔术方法以及关于独立实例与相连实例的全面讲解
2016/10/18 PHP
PHP7下协程的实现方法详解
2017/12/17 PHP
ThinkPHP5+UEditor图片上传到阿里云对象存储OSS功能示例
2019/08/05 PHP
thinkphp5使html5实现动态跳转的例子
2019/10/16 PHP
tp5.0框架隐藏index.php入口文件及模块和控制器的方法分析
2020/02/11 PHP
PHP时间相关常用函数用法示例
2020/06/03 PHP
清华大学出版的事半功倍系列 javascript全部源代码
2007/05/04 Javascript
js 创建书签小工具之理论
2011/02/25 Javascript
js数组Array sort方法使用深入分析
2013/02/21 Javascript
让浏览器DOM元素最后加载的js方法
2014/07/29 Javascript
javascript对中文按照拼音排序代码
2014/08/20 Javascript
深入探究使JavaScript动画流畅的一些方法
2015/06/30 Javascript
Uploadify上传文件方法
2016/03/16 Javascript
jQuery实现遍历复选框的方法示例
2017/03/06 Javascript
Scala解析Json字符串的实例详解
2017/10/11 Javascript
cordova入门基础教程及使用中遇到的一些问题总结
2017/11/14 Javascript
nodejs项目windows下开机自启动的方法
2017/11/22 NodeJs
js实现3D粒子酷炫动态旋转特效
2020/09/13 Javascript
Nest.js散列与加密实例详解
2021/02/24 Javascript
python使用paramiko实现远程拷贝文件的方法
2016/04/18 Python
windows下安装Python和pip终极图文教程
2017/03/05 Python
Python入门之后再看点什么好?
2018/03/05 Python
详解如何管理多个Python版本和虚拟环境
2019/05/10 Python
python进阶之自定义可迭代的类
2019/08/20 Python
python中对_init_的理解及实例解析
2019/10/11 Python
opencv python 图片读取与显示图片窗口未响应问题的解决
2020/04/24 Python
Python填充任意颜色,不同算法时间差异分析说明
2020/05/16 Python
致400米运动员广播稿
2014/02/07 职场文书
学校读书活动总结
2014/06/30 职场文书
群众路线领导班子四风对照检查材料
2014/09/27 职场文书
单位委托书
2014/10/15 职场文书
同学聚会通知书
2015/04/20 职场文书
酒店员工手册范本
2015/05/14 职场文书
Python 用户输入和while循环的操作
2021/05/23 Python