Python中的descriptor描述器简明使用指南

 更新时间:2016年06月02日 17:28:30   作者:人世间  
descriptor在Python中主要被用来定义方法和属性,使用起来相当具有技巧性,这里我们先从基础的开始,整理一份Python中的descriptor描述器简明使用指南

当定义迭代器的时候,描述是实现迭代协议的对象,即实现__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中四种关系图数据可视化的效果对比

    python关系图的可视化主要就是用来分析一堆数据中,每一条数据的节点之间的连接关系从而更好的分析出人物或其他场景中存在的关联关系。本文将制作四个不同的关系图的可视化效果,感兴趣的可以了解一下
    2022-11-11
  • python3.7 的新特性详解

    python3.7 的新特性详解

    这篇文章主要介绍了python3.7 的新特性详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-07-07
  • 使用PyCharm在Github上保存代码并在服务器上运行方式

    使用PyCharm在Github上保存代码并在服务器上运行方式

    这篇文章主要介绍了使用PyCharm在Github上保存代码并在服务器上运行方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-02-02
  • Python中10个常用的内置函数详解

    Python中10个常用的内置函数详解

    这篇文章主要为大家介绍了Python常用的内置函数,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2021-12-12
  • Python return语句如何实现结果返回调用

    Python return语句如何实现结果返回调用

    这篇文章主要介绍了Python return语句如何实现结果返回调用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • 初探TensorFLow从文件读取图片的四种方式

    初探TensorFLow从文件读取图片的四种方式

    本篇文章主要介绍了初探TensorFLow从文件读取图片的四种方式,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-02-02
  • Python中logging实例讲解

    Python中logging实例讲解

    在本篇文章里小编给大家分享的是关于Python中logging的详细介绍内容,有兴趣的朋友们跟着学习下。
    2019-01-01
  • python神经网络VGG16模型复现及其如何预测详解

    python神经网络VGG16模型复现及其如何预测详解

    这篇文章主要为大家介绍了VGG16模型的复现及其详解(包含如何预测),有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • python计算对角线有理函数插值的方法

    python计算对角线有理函数插值的方法

    这篇文章主要介绍了python计算对角线有理函数插值的方法,涉及Python数学运算的相关技巧,需要的朋友可以参考下
    2015-05-05
  • Python 合并多个TXT文件并统计词频的实现

    Python 合并多个TXT文件并统计词频的实现

    这篇文章主要介绍了Python 合并多个TXT文件并统计词频的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-08-08

最新评论