描述符__get__,__set__,__delete__和析构方法__del__
描述符__get__,__set__,__delete__
1、描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议
__get__():调用一个属性时,触发
__set__():为一个属性赋值时,触发
__delete__():采用del删除属性时,触发
描述就是一个新式类,这个类至少要实现上述三个方法的一个
class 描述符:
def __get__():
pass
def __set__():
pass
def __delete__():
pass class 类:
name=描述符() obj=类()
obj.name #get
obj.name='egon' #set
del obj.name #delete
2、描述符是干什么的:描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中)
class Foo:
def __get__(self, instance, owner):
print('触发get')
def __set__(self, instance, value):
print('触发set')
def __delete__(self, instance):
print('触发delete') class Bar:
x = Foo() #描述符必须写在类的属性中
def __init__(self,n):
self.x = n #包含这三个方法的新式类称为描述符,由这个类产生的实例进行属性的调用/赋值/删除,并不会触发这三个方法
f1=Foo() #并不会调用
f1.name='egon' #赋值
f1.name #调用
del f1.name #删除
b1 = Bar('b') #触发__set__
b1.x #触发__get__
总结:但凡是操作被代理的self.x都会找代理的类
3、描述符分两种
一 数据描述符:至少实现了__get__()和__set__()
1 class Foo:
2 def __set__(self, instance, value):
3 print('set')
4 def __get__(self, instance, owner):
5 print('get')
二 非数据描述符:没有实现__set__()
1 class Foo:
2 def __get__(self, instance, owner):
3 print('get')
4 描述符的参数
#Typep数据描述符
class Typep:
def __init__(self,name):
self.name = name
def __get__(self, instance, owner):
print('__get__执行')
self.instance = instance #instance 传过来的就是People类的一个实例,也就是p1
self.owner = owner #owner 传过来的就是instance的拥有者,也就是实例化对象的类 def __set__(self, instance, value):
print('__set__执行')
self.instance = instance #instance 传过来的就是People类的一个实例,也就是p1
#<__main__.People object at 0x000000EA07077208>
self.value = value #就是p1传入过来的name属性的值
#zhaok
print(self)
instance.__dict__[self.name]=value def __delete__(self, instance):
print('__delete__执行')
self.instance = instance class People:
name = Typep('name') #name被Typep数据描述符代理,被代理过后的所有对name的操作都会去找代理类
def __init__(self,name,age,sal): #触发过后,正常传值,但是name被代理 数据描述符优先级高于实例属性
self.name = name
self.age = age
self.sal = sal p1 = People('zhaok',18,33.3) #实例化一个对象p1 实例化会触发People类的构造方法也就是__init__方法
5 注意事项:
一 描述符本身应该定义成新式类,被代理的类也应该是新式类
二 必须把描述符定义成这个类的类属性,不能为定义到构造函数中
三 要严格遵循该优先级,优先级由高到底分别是
1.类属性
2.数据描述符
3.实例属性
4.非数据描述符
5.找不到的属性触发__getattr__()
#描述符Str
class Str:
def __get__(self, instance, owner):
print('Str调用')
def __set__(self, instance, value):
print('Str设置...')
def __delete__(self, instance):
print('Str删除...') class People:
name=Str()
def __init__(self,name,age): #name被Str类代理,age被Int类代理,
self.name=name
self.age=age #基于上面的演示,我们已经知道,在一个类中定义描述符它就是一个类属性,存在于类的属性字典中,而不是实例的属性字典 #那既然描述符被定义成了一个类属性,直接通过类名也一定可以调用吧,没错
People.name #恩,调用类属性name,本质就是在调用描述符Str,触发了__get__() People.name='egon' #那赋值呢,我去,并没有触发__set__()
del People.name #赶紧试试del,我去,也没有触发__delete__()
#结论:描述符对类没有作用-------->傻逼到家的结论 '''
原因:描述符在使用时被定义成另外一个类的类属性,因而类属性比二次加工的描述符伪装而来的类属性有更高的优先级
People.name #恩,调用类属性name,找不到就去找描述符伪装的类属性name,触发了__get__() People.name='egon' #那赋值呢,直接赋值了一个类属性,它拥有更高的优先级,相当于覆盖了描述符,肯定不会触发描述符的__set__()
del People.name #同上
''' 类属性>数据描述符
类属性>数据描述符
#描述符Str
class Str:
def __get__(self, instance, owner):
print('Str调用')
def __set__(self, instance, value):
print('Str设置...')
def __delete__(self, instance):
print('Str删除...') class People:
name=Str()
def __init__(self,name,age): #name被Str类代理,age被Int类代理,
self.name=name
self.age=age p1=People('egon',18) #如果描述符是一个数据描述符(即有__get__又有__set__),那么p1.name的调用与赋值都是触发描述符的操作,于p1本身无关了,相当于覆盖了实例的属性
p1.name='egonnnnnn'
p1.name
print(p1.__dict__)#实例的属性字典中没有name,因为name是一个数据描述符,优先级高于实例属性,查看/赋值/删除都是跟描述符有关,与实例无关了
del p1.name
数据描述符>实例属性
class Foo:
def func(self):
print('我胡汉三又回来了')
f1=Foo()
f1.func() #调用类的方法,也可以说是调用非数据描述符
#函数是一个非数据描述符对象(一切皆对象么)
print(dir(Foo.func))
print(hasattr(Foo.func,'__set__'))
print(hasattr(Foo.func,'__get__'))
print(hasattr(Foo.func,'__delete__'))
#有人可能会问,描述符不都是类么,函数怎么算也应该是一个对象啊,怎么就是描述符了
#笨蛋哥,描述符是类没问题,描述符在应用的时候不都是实例化成一个类属性么
#函数就是一个由非描述符类实例化得到的对象
#没错,字符串也一样 f1.func='这是实例属性啊'
print(f1.func) del f1.func #删掉了非数据
f1.func()
实例属性>非数据描述符
class Foo:
def __set__(self, instance, value):
print('set')
def __get__(self, instance, owner):
print('get')
class Room:
name=Foo()
def __init__(self,name,width,length):
self.name=name
self.width=width
self.length=length #name是一个数据描述符,因为name=Foo()而Foo实现了get和set方法,因而比实例属性有更高的优先级
#对实例的属性操作,触发的都是描述符的
r1=Room('厕所',1,1)
r1.name
r1.name='厨房' class Foo:
def __get__(self, instance, owner):
print('get')
class Room:
name=Foo()
def __init__(self,name,width,length):
self.name=name
self.width=width
self.length=length #name是一个非数据描述符,因为name=Foo()而Foo没有实现set方法,因而比实例属性有更低的优先级
#对实例的属性操作,触发的都是实例自己的
r1=Room('厕所',1,1)
r1.name
r1.name='厨房'
再次验证:实例属性>非数据描述符
class Foo:
def func(self):
print('我胡汉三又回来了') def __getattr__(self, item):
print('找不到了当然是来找我啦',item)
f1=Foo() f1.xxxxxxxxxxx
非数据描述符>找不到
6 描述符使用
众所周知,python是弱类型语言,即参数的赋值没有类型限制,下面我们通过描述符机制来实现类型限制功能
#Typep数据描述符
class Typep:
def __init__(self,key,expected_type):
self.key = key
self.expected_type = expected_type
def __get__(self, instance, owner):
print('__get__执行')
# self.instance = instance #instance 传过来的就是People类的一个实例,也就是p1
# self.owner = owner #owner 传过来的就是instance的拥有者,也就是实例化对象的类
return instance.__dict__[self.key] #返回p1key值对应的value值 def __set__(self, instance, value):
print('__set__执行')
# self.instance = instance #instance 传过来的就是People类的一个实例,也就是p1
#<__main__.People object at 0x000000EA07077208>
# self.value = value #就是p1传入过来的name属性的值
#zhaok
if not isinstance(value,self.expected_type): #判断如果传入的信息,不是想要的类型
raise TabError('你传入的%s不是%s类型'%(value,self.expected_type)) #直接抛出异常,终止服务
instance.__dict__[self.key]=value #p1.__dict__[key] = value #如果是,直接写入字典中 def __delete__(self, instance):
print('__delete__执行')
# self.instance = instance
instance.__dict__.pop[self.key] #删除
class People:
name = Typep('name',str) #name被Typep数据描述符代理,被代理过后的所有对name的操作都会去找代理类
age = Typep('age',int)
def __init__(self,name,age,sal): #触发过后,正常传值,但是name被代理 数据描述符优先级高于实例属性
self.name = name
self.age = age
self.sal = sal p1 = People('zhaok',18,33.3) #实例化一个对象p1 实例化会触发People类的构造方法也就是__init__方法
print(p1.name)
__del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
简单示范:
class Foo:
def __del__(self):
print('执行我啦')
f1=Foo()
del f1
print('------->')
#输出结果
执行我啦
------->
描述符__get__,__set__,__delete__和析构方法__del__的更多相关文章
- 描述符__get__,__set__,__delete__
描述符__get__,__set__,__delete__ # 描述符:1用来代理另外一个类的属性 # __get__():调用一个属性时,触发 # __set__():为一个属性赋值时触发 # __ ...
- python基础----再看property、描述符(__get__,__set__,__delete__)
一.再看property 一个静态属性property ...
- 描述符__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__)简介
先说定义,这里直接翻译官方英文文档: 一般来说,描述符是具有“绑定行为”的对象属性,该对象的属性访问将会被描述符协议中的方法覆盖.这些方法是__get__(),__set__(),和__delete_ ...
- Python类总结-描述符__get__(),__set__(),__delete__()
1 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),set(),delete()中的一个,这也被称为描述符协议 get():调用一个属性时,触发 set():为一 ...
- __get__ __set__ __delete__描述符
描述符就是一个新式类,这个类至少要实现__get__ __set__ __delete__方法中的一种class Foo: def __get__(self, instance, owner): pr ...
- (转)ORA-12514 TNS 监听程序当前无法识别连接描述符中请求服务 的解决方法
早上同事用PL/SQL连接虚拟机中的Oracle数据库,发现又报了"ORA-12514 TNS 监听程序当前无法识别连接描述符中请求服务"错误,帮其解决后,发现很多人遇到过这样的问 ...
- 描述符(__get__和__set__和__delete__)
目录 一.描述符 二.描述符的作用 2.1 何时,何地,会触发这三个方法的执行 三.两种描述符 3.1 数据描述符 3.2 非数据描述符 四.描述符注意事项 五.使用描述符 5.1 牛刀小试 5.2 ...
随机推荐
- office web apps的搭建部署(1)(写于2017.12.27)
因为业务方面的需求,项目要求搭建office-web-apps这个玩意儿,做一个在线预览编辑的功能,为了方便,我下面都用OWA代替这个服务. 首先说一下什么是office-web-apps-serve ...
- SVN版本控制中.a无法提交问题
1.首先xcode是默认忽略.a文件的.改变方法如下: 1⃣️. 打开终端, 在命令行中输入: vi ~/.subversion/config 来打开配置文件.2⃣️. 然后, 在[miscell ...
- Linux服务器Java输出文件中文乱码
使用下面语句查看编码: String encoding = System.getProperty("file.encoding");结果输出:ANSI_X3.4-1968,从而导致 ...
- HDU5968 异或密码 —— 二分 + 边界的细节处理
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5968 异或密码 Time Limit: 2000/1000 MS (Java/Others) M ...
- ansible-playbook unarchive模块
先 进行 pause模块的 记录: pause 在playbook执行的过程中暂停一定时间或者提示用户进行某些操作 常用参数: minutes:暂停多少分钟 seconds:暂停多少秒 prompt ...
- 卸载asterisk 会装就要会卸载 你会吗? [跟我一起学](转安静的发狂者)
1 针对用编译的方式安装时的卸载 第一步 :先停止你的asterisk >asterisk -rx ‘stop now’然后要验证一下是否真的被停了. >ps aux|grep “as ...
- JQ对象和原生DOM对象
相同点:两者本质上都是DOM元素. 不同点:JQ对象是在原生DOM对象上进行了一次封装,使开发人员使用起来更简洁.高效. 两者之间用法也完全不同,很说初学者经常混淆. 其实区分两者并不难, 1.语法不 ...
- float和Float的区别
float是基本数据类型,Float是包装类(封装类).封装类可将接本数据类型封装后当作对象进行操作,并为各种基本数据类型提供各种转换功能.例如Float f = new Float(3.4f);,即 ...
- URAL 1996 Cipher Message 3
题目 神题. 记得当初DYF和HZA讲过一个FFT+KMP的题目,一直觉得很神,从来没去做. 没有真正理解FFT的卷积. 首先考虑暴力. 只考虑前7位 KMP 找出所有 B 串可以匹配 A 串的位置. ...
- SpannableStringBuilder 用法浅析以及仿陌陌表情
SpannableStringBuilder 官方文档解释:这个类可以使文本的内容和标记都可以改变.当我们要为TextView或者Edittext里面的文字加入加入一些效果,如下划线,颜色标 识,超 ...