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@修饰符的文章可 ...
随机推荐
- SQLite3动态库、静态库编译
资源准备 1.下载SQLite3源码,下载地址为https://www.sqlite.org/download.html.下载sqlite-amalgamation-3200000.zip和sqlit ...
- vim基本命令速查表
来源:https://github.com/skywind3000/awesome-cheatsheets/blob/master/editors/vim.txt ################## ...
- Microsoft.Office.Interop.Excel 导出Excel
; ; /// <summary> /// 使用 Excel.dll 导出 Excel /// </summary> /// <param name="list ...
- c#中在函数后紧跟=>,几个意思,差点懵逼到没有朋友!
以下是一段新建.net core web中的代码: namespace TempCoreApp { public class Program { public static void Main(str ...
- ASP.NET Core 2 学习笔记(四)依赖注入
ASP.NET Core使用了大量的依赖注入(Dependency Injection, DI),把控制反转(Inversion Of Control, IoC)运用的相当巧妙.DI可算是ASP.NE ...
- Win(Phone)10开发第(4)弹,HTTP 实时流播放 m3u8
其实这篇只有一句话,win10原生支持HLS啦 1 2 3 AdaptiveMediaSourceCreationResult amsResult = await AdaptiveMediaSourc ...
- Day 5 字典的操作
1. 例子 ,务必理解 dic = { 'name':'金鑫', 'name_list':[1,2,3,'李杰'], 1:{ 'python10':['小黑','萌哥'], '老男孩':{'name' ...
- yum 安装指定 kernel 版本源码
yum install "kernel-devel-uname-r == $(uname -r)"
- 902. Numbers At Most N Given Digit Set
We have a sorted set of digits D, a non-empty subset of {'1','2','3','4','5','6','7','8','9'}. (Not ...
- 898. Bitwise ORs of Subarrays
We have an array A of non-negative integers. For every (contiguous) subarray B = [A[i], A[i+1], ..., ...