先说定义,这里直接翻译官方英文文档:

  一般来说,描述符是具有“绑定行为”的对象属性,该对象的属性访问将会被描述符协议中的方法覆盖.这些方法是__get__(),__set__(),和__delete__().如果一个对象定义了这些方法中的任何一个,它就是一个描述符.

接下来对这个定义进行解释:

  我们访问一个对象a的属性x的时候,是这么调用的:a.x,那么这种方便的调用方式其实是怎么工作的呢?

  首先,它会访问自己的实例名称空间:

    a.__dict__['x']

  如果没有,则会访问类及超类的名称空间, 大致上是这个意思:

for cls in type(a).__mro__:
if hasattr(cls, 'x'):
return cls.__dict__['x']

  但如果该属性绑定了一个带有__get__的类的实例化对象,这个时候,b.x的工作方式就与上面不同了:

class Desc:
val = 1 def __get__(self, instance, owner):
return self.val class B:
x = Desc() b = B()
# b.x调用路径:type(b).__dict__['x'].__get__(b, type(b))
# 需要注意的一点是,定义了描述符之后,在构造方法里为同名变量赋值是无效的
print(b.x)
>>>1

  这是怎么实现的呢?要解释清楚这个原理,要先说明一下__getattribute__函数,当我们调用一个属性的时候,底层其实就是在执行该函数,该函数的工作方式是:

  B.x => B.__dict__['x'] => 如果 存在__get__方法 则 B.__dict__['x'].__get__(None, B)

  具体代码如下:

def __getattribute__(self, key):
"Emulate type_getattro() in Objects/typeobject.c"
v = object.__getattribute__(self, key)
if hasattr(v, '__get__'):
return v.__get__(None, self)
return v

  所以, 我们给B.x绑定改的是一个对象,返回的却是该对象的__get__方法的返回值,重写这个函数,我们就可以停止描述符的调用.

  接下来再解释__set__:

class Desc:
num = 1 def __get__(self, instance, owner):
return self.num def __set__(self, instance, value):
self.num += value class B:
x = Desc() b = B()
b.x = 2
print(b.x)
>>>3

  我们给b.x赋值为2,结果输出的b.x则为3,神奇吗?

  这个概念可能不太好理解,其原因是这里的'='符号被重载了,不再是赋值的意思.

  如果B.__dict__['x']中没有__set__方法,'='符号则执行其父类的__set__,一般来说,就是正常的赋值.

  如果B.__dict__['x']重写了__set__方法,'='符号则执行该重写的方法,即B.__dict__['x'].__set__(None, value)

  利用这一特性,我们可以在python程序中创建常量, 只需要在__set__方法里抛出一个异常即可.

  至于 __delete__,在del b.x时会触发,如果未定义,则报错

ps: Properties, bound methods, static methods,  class methods都是描述符协议的应用.欲知后事如何,请看英文文档:https://docs.python.org/3/howto/descriptor.html

Python描述符(__get__,__set__,__delete__)简介的更多相关文章

  1. python基础----再看property、描述符(__get__,__set__,__delete__)

    一.再看property                                                                          一个静态属性property ...

  2. 描述符__get__,__set__,__delete__和析构方法__del__

    描述符__get__,__set__,__delete__ 1.描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一 ...

  3. 描述符__get__,__set__,__delete__

    描述符__get__,__set__,__delete__ # 描述符:1用来代理另外一个类的属性 # __get__():调用一个属性时,触发 # __set__():为一个属性赋值时触发 # __ ...

  4. 描述符__get__(),__set__(),__delete__()(三十七)

    http://www.cnblogs.com/linhaifeng/articles/6204014.html#_label12 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__ ...

  5. python小知识-__call__和类装饰器的结合使用,数据描述符__get__\__set__\__delete__(描述符类是Python中一种用于储存类属性值的对象)

    class Decorator(): def __init__(self, f): print('run in init......') self.f = f def __call__(self, a ...

  6. Python类总结-描述符__get__(),__set__(),__delete__()

    1 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),set(),delete()中的一个,这也被称为描述符协议 get():调用一个属性时,触发 set():为一 ...

  7. python 描述符 上下文管理协议 类装饰器 property metaclass

    1.描述符 #!/usr/bin/python env # coding=utf-8 # 数据描述符__get__ __set__ __delete__ ''' 描述符总结 描述符是可以实现大部分py ...

  8. __get__ __set__ __delete__描述符

    描述符就是一个新式类,这个类至少要实现__get__ __set__ __delete__方法中的一种class Foo: def __get__(self, instance, owner): pr ...

  9. 【转载】Python 描述符简介

    来源:Alex Starostin 链接:www.ibm.com/developerworks/cn/opensource/os-pythondescriptors/ 关于Python@修饰符的文章可 ...

随机推荐

  1. SQL 取两日期的记录

    SELECT TOP 1000 [ID]      ,[SourcePageID]      ,[PlatformType]      ,[CreateTime]  FROM [home_sendor ...

  2. 反射导出 Excel

    /// <summary> /// List 数据导出Excel /// </summary> /// <param name="list">数 ...

  3. NET 集合分页查询

    参数: var list = new List<int>(); // 集合 ; // 总数量 ; // 每页查询数量 第一种: ? totalCount / pageSize : tota ...

  4. 使用ABP框架踩过的坑系列3

    从架构角度来讲,ApplicationService究竟应该如何定位,一种说法是直接对应用例UseCase, 也就是直接对应UI, 这个UI是广义的,不仅仅是浏览器的页面,也包括API调用.还是从我曾 ...

  5. centos7 虚拟机中,网卡不启动的解决方式

    使用NAT模式的虚拟centos, 只显示两个网卡,无法连接外网, 输入systemctl start network后报错信息" Restarting network (via syste ...

  6. OSX - 可以安装任何程序!

    在shell里面执行命令: sudo spctl --master-disable 参考: https://www.jianshu.com/p/010cc30228f3

  7. “全栈2019”Java多线程第二十四章:等待唤醒机制详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  8. java删除字符串最后一个字符的几种方法

    偶然看到的,记录一下,以免忘记 字符串:string s = "1,2,3,4,5," 目标:删除最后一个 "," 方法:    1.用的最多的是Substri ...

  9. 《Python黑帽子:黑客与渗透测试编程之道》 Web攻击

    Web的套接字函数库:urllib2 一开始以urllib2.py命名脚本,在Sublime Text中运行会出错,纠错后发现是重名了,改过来就好: #!/usr/bin/python #coding ...

  10. 队列的实现——c++

    一.介绍 队列(Queue),是一种线性存储结构.它有以下几个特点:(01) 队列中数据是按照"先进先出(FIFO, First-In-First-Out)"方式进出队列的.(02 ...