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

  一般来说,描述符是具有“绑定行为”的对象属性,该对象的属性访问将会被描述符协议中的方法覆盖.这些方法是__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. netty--NioEventLoop滴干活

    netty是最近项目要用到的nio框架,找了各种资料,发现称赞它的有点多,所以决定用它:其实也就二选一嘛,mina或netty或自己写.对于mina,也不熟,不过看各种介绍,貌似netty干活还是很不 ...

  2. LinkServer--服务器选项

    1. RPC和RPC out 当RPC和RPC out被设置为true时,允许调用远程服务器的存储过程 2.为RPC启用针对分布式事务的升级 使用该选项可通过 Microsoft 分布式事务处理协调器 ...

  3. NetCore入门篇:(十一)NetCore项目读取配置文件appsettings.json

    一.简介 1.读取配置文件是开发过程中使用非常频繁的操作.属称”不能写死“ 二.NetCore读取配置文件 1.新建一个静态公共变量,属称单例. 2.在程序Startup启动时,将系统变量传递给单例. ...

  4. 构建NetCore应用框架之实战篇(七):BitAdminCore框架登录功能源码解读

    本篇承接上篇内容,如果你不小心点击进来,建议从第一篇开始完整阅读,文章内容继承性连贯性. 构建NetCore应用框架之实战篇系列 一.简介 1.登录功能完成后,框架的雏形已经形成,有必要进行复习. 2 ...

  5. css 可拖拽列表

    <!DOCTYPE HTML> <html><head> <meta charset="UTF-8"> <title>d ...

  6. C#多线程编程系列(三)- 线程同步

    目录 1.1 简介 1.2 执行基本原子操作 1.3 使用Mutex类 1.4 使用SemaphoreSlim类 1.5 使用AutoResetEvent类 1.6 使用ManualResetEven ...

  7. Day 38 Semaphore ,Event ,队列

    什么是信号量(multiprocess.Semaphore) 互斥锁同时只允许一个线程更改数据,而信号量semaphore是同时允许一定数量的线程更改数据. 假设商场里有4个迷你唱吧 ,所以通过同时可 ...

  8. session和cookie的异同

    Cookie是服务器发给客户端的一小段文本,保存在浏览器所在客户端的内存和磁盘上.服务器可以从客户端读出这些cookie.通过cookie,客户端可以和服务器端建立起一种联系,也就是说,Cookie是 ...

  9. “全栈2019”Java多线程第二十二章:饥饿线程(Starvation)详解

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

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

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