Python描述符(__get__,__set__,__delete__)简介
先说定义,这里直接翻译官方英文文档:
一般来说,描述符是具有“绑定行为”的对象属性,该对象的属性访问将会被描述符协议中的方法覆盖.这些方法是__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__)简介的更多相关文章
- python基础----再看property、描述符(__get__,__set__,__delete__)
一.再看property 一个静态属性property ...
- 描述符__get__,__set__,__delete__和析构方法__del__
描述符__get__,__set__,__delete__ 1.描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一 ...
- 描述符__get__,__set__,__delete__
描述符__get__,__set__,__delete__ # 描述符:1用来代理另外一个类的属性 # __get__():调用一个属性时,触发 # __set__():为一个属性赋值时触发 # __ ...
- 描述符__get__(),__set__(),__delete__()(三十七)
http://www.cnblogs.com/linhaifeng/articles/6204014.html#_label12 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__ ...
- python小知识-__call__和类装饰器的结合使用,数据描述符__get__\__set__\__delete__(描述符类是Python中一种用于储存类属性值的对象)
class Decorator(): def __init__(self, f): print('run in init......') self.f = f def __call__(self, a ...
- Python类总结-描述符__get__(),__set__(),__delete__()
1 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),set(),delete()中的一个,这也被称为描述符协议 get():调用一个属性时,触发 set():为一 ...
- python 描述符 上下文管理协议 类装饰器 property metaclass
1.描述符 #!/usr/bin/python env # coding=utf-8 # 数据描述符__get__ __set__ __delete__ ''' 描述符总结 描述符是可以实现大部分py ...
- __get__ __set__ __delete__描述符
描述符就是一个新式类,这个类至少要实现__get__ __set__ __delete__方法中的一种class Foo: def __get__(self, instance, owner): pr ...
- 【转载】Python 描述符简介
来源:Alex Starostin 链接:www.ibm.com/developerworks/cn/opensource/os-pythondescriptors/ 关于Python@修饰符的文章可 ...
随机推荐
- 常用kubectl命令总结
command kubectl kubectl 输出格式 显示Pod的更多信息 kubectl get pod <pod-name> -o wide 以yaml格式显示Pod的详细信息 k ...
- signalR常见问题
一.安装signalR会对应安装自己的NewJson包,如果引用了含有不同NewJson包的dll组件,会造成版本不一致.必须在运行环境中指出使用目标版本. 问题截图: 解决方式: <runti ...
- DataSet转换成List<>
方法一: //DataSet转换成List<ArticleInfo> public List<ArticleInfo> GetArticleList(DataSet ds) { ...
- Ruby for Sketchup 贪吃蛇演示源码(naive_snake)
sketchup是非常简单易用的三维建模软件,可以利用ruby 做二次开发, api文档 http://www.rbc321.cn/api 今天在su中做了一款小游戏 贪吃蛇,说一下步骤 展示 主要思 ...
- cpu缓存java性能问题初探
在内存与cpu寄存器之间,还有一块区域叫做cpu高速缓存,即我们常常说的cache. cache分为L1.L2.L3三级缓存,速度递减,离cpu越来越远,L1.L2每个内核自己都有,L3是每个插槽上的 ...
- ko内核模块文件以及载入模块命令modprobe insmod
原文链接:https://blog.csdn.net/evenness/article/details/7655921?utm_source=blogxgwz5 modprobe: Load modu ...
- 三个分段的.tar.gz文件,合并并解压
1.合并使用spilt分割的文件 # cat sxrt5.0.dvd1.tar.gzaa sxrt5.0.dvd1.tar.gzab sxrt5.0.dvd1.tar.gzac >>sxr ...
- extjs4.0以上添加多行工具栏的方法
4.0.0起提供了dockedItems ,只要写两个dockItem,xtype为'toolbar',dock为 'top'即可
- Kafka数据可靠性与一致性解析
Partition Recovery机制 每个Partition会在磁盘记录一个RecoveryPoint, 记录已经flush到磁盘的最大offset.broker fail 重启时,会进行load ...
- webpack快速入门——配置JS压缩,打包
1 .首先在webpack.config.js中引入 const uglify = require('uglifyjs-webpack-plugin'); 2.然后在plugins配置里 plugin ...