在 Python 众多原生特性中,描述符可能是最少被自定义的特性之一,但它在底层实现的方法和属性却无时不刻被使用着,它优雅的实现方式体现出 Python 简洁之美。

定义

  • 一个描述符是一个有"绑定行为"的对象属性(object attribute),它的访问控制会被描述器协议方法重写。
  • 任何定义了 __get__, __set__ 或者 __delete__ 任一方法的类称为描述符类,其实例对象便是一个描述符,这些方法称为描述符协议。
  • 当对一个实例属性进行访问时,Python 会按 obj.__dict__type(obj).__dict__type(obj)的父类.__dict__ 顺序进行查找,如果查找到目标属性并发现是一个描述符,Python 会调用描述符协议来改变默认的控制行为。
  • 描述符是 @property @classmethod @staticmethodsuper 的底层实现机制。

特性

  • 同时定义了 __get____set__ 的描述符称为 数据描述符(data descriptor);仅定义了 __get__ 的称为 非数据描述符(non-data descriptor) 。两者区别在于:如果 obj.__dict__ 中有与描述符同名的属性,若描述符是数据描述符,则优先调用描述符,若是非数据描述符,则优先使用 obj.__dict__ 中属性。
  • 描述符协议必须定义在类的层次上,否则无法被自动调用。

描述符协议

__get__(self, instance, owner)

_:param self: _描述符对象本身

_:param instance: _使用描述符的对象的实例

_:param owner: _使用描述符的对象拥有者

__set__(self, instance, value)

_:param value: _对描述符的赋值

__delete__(self, instance)

实例

class LazyProperty(object):
"""
实现惰性求值(访问时才计算,并将值缓存)
利用了 obj.__dict__ 优先级高于 non-data descriptor 的特性
第一次调用 __get__ 以同名属性存于实例字典中,之后就不再调用 __get__
"""
def __init__(self, fun):
self.fun = fun def __get__(self, instance, owner):
if instance is None:
return self
value = self.fun(instance)
setattr(instance, self.fun.__name__, value)
return value class ReadonlyNumber(object):
"""
实现只读属性(实例属性初始化后无法被修改)
利用了 data descriptor 优先级高于 obj.__dict__ 的特性
当试图对属性赋值时,总会先调用 __set__ 方法从而抛出异常
"""
def __init__(self, value):
self.value = value def __get__(self, instance, owner):
return self.value def __set__(self, instance, value):
raise AttributeError(
"'%s' is not modifiable" % self.value
) class Circle(object): pi = ReadonlyNumber(3.14) def __init__(self, radius):
self.radius = radius @LazyProperty
def area(self):
print('Computing area')
return self.pi * self.radius ** 2

参考文章

https://pyzh.readthedocs.io/en/latest/Descriptor-HOW-TO-Guide.html


欢迎关注

编程思维不应只存留在代码之中,更应伴随于整个人生旅途,这个公众号不只聊技术,还会聊产品/互联网/经济学等广泛话题,所以也欢迎非程序员关注。

Python 描述符(Descriptor) 附实例的更多相关文章

  1. python描述符(descriptor)、属性(property)、函数(类)装饰器(decorator )原理实例详解

     1.前言 Python的描述符是接触到Python核心编程中一个比较难以理解的内容,自己在学习的过程中也遇到过很多的疑惑,通过google和阅读源码,现将自己的理解和心得记录下来,也为正在为了该问题 ...

  2. Python 描述符(descriptor) 杂记

    转自:https://blog.tonyseek.com/post/notes-about-python-descriptor/ Python 引入的“描述符”(descriptor)语法特性真的很黄 ...

  3. python描述符descriptor(一)

    Python 描述符是一种创建托管属性的方法.每当一个属性被查询时,一个动作就会发生.这个动作默认是get,set或者delete.不过,有时候某个应用可能会有 更多的需求,需要你设计一些更复杂的动作 ...

  4. python描述符 descriptor

    descriptor 在python中,如果一个新式类定义了__get__, __set__, __delete__方法中的一个或者多个,那么称之为descriptor.descriptor通常用来改 ...

  5. Python 描述符 (descriptor)

    1.什么是描述符? 描述符是Python新式类的关键点之一,它为对象属性提供强大的API,你可以认为描述符是表示对象属性的一个代理.当需要属性时,可根据你遇到的情况,通过描述符进行访问他(摘自Pyth ...

  6. Python描述符 (descriptor) 详解

    1.什么是描述符? python描述符是一个“绑定行为”的对象属性,在描述符协议中,它可以通过方法重写属性的访问.这些方法有 __get__(), __set__(), 和__delete__().如 ...

  7. python描述符descriptor(二)

    python内置的描述符 python有些内置的描述符对象,property.staticmethod.classmethod,python实现如下: class Property(object): ...

  8. 【python】描述符descriptor

    开始看官方文档,各种看不懂,只看到一句Properties, bound and unbound methods, static methods, and class methods are all ...

  9. python理解描述符(descriptor)

    Descriptor基础 python中的描述符可以用来定义触发自动执行的代码,它像是一个对象属性操作(访问.赋值.删除)的代理类一样.前面介绍过的property是描述符的一种. 大致流程是这样的: ...

随机推荐

  1. 接口测试02 - 无法绕过的json解析

    概述: 先瞧一下什么是json.JSON(JavaScript Object Notation,JS对象标记)是一种轻量级的数据交换格式. 它基于ECMAScript(w3c定制的js规范)的一个子集 ...

  2. 上白泽慧音——tarjian

    题目描述 在幻想乡,上白泽慧音是以知识渊博闻名的老师.春雪异变导致人间之里的很多道路都被大雪堵塞,使有的学生不能顺利地到达慧音所在的村庄.因此慧音决定换一个能够聚集最多人数的村庄作为新的教学地点.人间 ...

  3. git与GitHub(二)

    昨天在安装完git之后,出了一个问题,虽然暂时有解决的办法,但是由于电脑中了病毒并且配置低下等原因,这个问题的解决办法目前还有待考证.遇到的问题是这样的: 前提是想试一下git在命令行里的命令:于是: ...

  4. CF1093D Beautiful Graph

    思路: 题目倒是没啥好说的,就是注意memset的效率问题.如果循环多次调用memset去初始化一个比较大的数组,那就会很费时间.就是因为这个被hack了.:( 实现: #include <bi ...

  5. 华硕笔记本刷BIOS

    笔记本硬件升级后想使用微软的Windows xp mode,之后发现笔记本BIOS中没有虚拟化选项,想通过升级BIOS的方法来解决,结果失败. 升级后出现关机后无法关闭电源指示灯以及风扇的问题,之后只 ...

  6. UVA 10572 Black & White (状压DP)

    题意:有一个n*m的矩阵,其中部分格子已经涂黑,部分涂白,要求为其他格子也上黑/白色,问有多少种涂法可以满足一下要求: (1)任意2*2的子矩阵不可以同色. (2)所有格子必须上色. (3)只能有两个 ...

  7. 二级域名绑定ECS

    关于阿里云域名的绑定,下面是个人的理解,如有错误请指出. 首先,任何域名都需要在阿里云备案后才可以使用, 如果是二级域名,不能单独备案,需要其顶级域名在阿里云备案. http://help.aliyu ...

  8. java读取clob字段的几种方法(转)

    http://blog.csdn.net/tanksyg/article/details/49927897 第一种 Clob clob = rs.getClob("remark") ...

  9. 字符串赋值方式理解 sizeof 和strlen的一些区别

    #include<stdio.h>#include<string.h>  int main(){ int a,i=0; char ch[10000]; while(scanf( ...

  10. poj1338 Ugly Numbers 打表, 递推

    题意:一个数的质因子能是2, 3, 5, 那么这个数是丑数. 思路: 打表或者递推. 打表: 若该数为丑数,那么一定能被2 或者3, 或者5 整除, 除完之后则为1. #include <ios ...