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@修饰符的文章可 ...
随机推荐
- Python2.7升级至Python3.6
Python2.7升级至Python3.6 今天在CentOS7.2上将python2.7升级至python3.6时遇到了诸多问题,下面将升级步骤以及解决方法一一列举. 1.安装Python3.6 安 ...
- [LeetCode 题解]: Binary Tree Preorder Traversal
前言 [LeetCode 题解]系列传送门: http://www.cnblogs.com/double-win/category/573499.html 1.题目描述 Given a bi ...
- c# WPF客户端调用WebAPI并转换成List
利用HttpClient.JsonConvert实现. 引用Newtonsoft.Json.dll和System.Net.Http. 举个例子:从webapi中获取设备列表. public parti ...
- SQL语句中的TOP(expression) [PERCENT] [WITH TIES] 用法
TOP(expression) [PERCENT] [WITH TIES] expression : 指定返回行数的数值表达式.如果指定了PERCENT,则expression默认转换为FLOAT值, ...
- Day 43数据库(Day1)
创建表. create table student( id int not null auto_increment PRIMARY key, name archar() not null, age i ...
- HDU4622 Reincarnation
题目链接:戳我 因为对应的很多询问,所以我们一定要将每一种询问先处理出来,然后O(1)查询. 至于怎么处理出来子串的子串呢? 我们固定左端点,然后依次加入子串即可.然后统计的时候直接统计last那一个 ...
- keepalive 原理讲解
keepalive 我们说到keepalive的时候,需要先明确一点,这个keepalive说的是tcp的还是http的. tcp的keepalive是侧重在保持客户端和服务端的连接,一方会不定期发送 ...
- A Tool To Plot Mathematical Function
Plot.cs using Microsoft.ClearScript; using Microsoft.ClearScript.V8; using Microsoft.Win32; using Sy ...
- java之JIT(Just in time)
Java程序最初是通过解释器进行解释执行的,当虚拟机发现某个方法或代码块运行的特别频繁时,会把这些代码认定为“热点代码”(Hot Spot Code).为了提高热点代码的执行效率,在运行时,虚拟机会把 ...
- ACTIVEMQ监控项目admin队列详情中文乱码
一.使用ACTIVEMQ队列,传入ObjectMessage时,监控项目admin无法解析消息信息,需要将消息javabean打成jar放入lib文件夹中,重启ACTIVEMQ,注意javabean要 ...