飒飒

六、描述符

1 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议
__get__():调用一个属性时,触发
__set__():为一个属性赋值时,触发
__delete__():采用del删除属性时,触发

class Foo: #在python3中Foo是新式类,它实现了三种方法,这个类就被称作一个描述符
def __get__(self, instance, owner):
pass
def __set__(self, instance, value):
pass
def __delete__(self, instance):
pass

定义一个描述符

2 描述符是干什么的:描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中)

class Foo:
def __get__(self, instance, owner):
print('触发get')
def __set__(self, instance, value):
print('触发set')
def __delete__(self, instance):
print('触发delete') #包含这三个方法的新式类称为描述符,由这个类产生的实例进行属性的调用/赋值/删除,并不会触发这三个方法
f1=Foo()
f1.name='egon'
f1.name
del f1.name
#疑问:何时,何地,会触发这三个方法的执行

引子:描述符类产生的实例进行属性操作并不会触发三个方法的执行

#描述符Str
class Str:
def __get__(self, instance, owner):
print('Str调用')
def __set__(self, instance, value):
print('Str设置...')
def __delete__(self, instance):
print('Str删除...') #描述符Int
class Int:
def __get__(self, instance, owner):
print('Int调用')
def __set__(self, instance, value):
print('Int设置...')
def __delete__(self, instance):
print('Int删除...') class People:
name=Str()
age=Int()
def __init__(self,name,age): #name被Str类代理,age被Int类代理,
self.name=name
self.age=age #何地?:定义成另外一个类的类属性 #何时?:且看下列演示 p1=People('alex',18) #描述符Str的使用
p1.name
p1.name='egon'
del p1.name #描述符Int的使用
p1.age
p1.age=18
del p1.age #我们来瞅瞅到底发生了什么
print(p1.__dict__)
print(People.__dict__) #补充
print(type(p1) == People) #type(obj)其实是查看obj是由哪个类实例化来的
print(type(p1).__dict__ == People.__dict__)

描述符应用之何时?何地?

3 描述符分两种
一 数据描述符:至少实现了__get__()和__set__()

1class 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')
class Foo:
name=2
def __get__(self, instance, owner):
print('get方法')
print(instance)
print(owner)
def __set__(self, instance, value):
print('set方法',value)
print(instance)
#instance.__dict__[self]=value #b1.__dict__
instance.__dict__['x'] = value
def __delete__(self, instance):
print('del方法')
print(instance)
class Bar:
x=Foo() #必须把描述符定义成这个的类属性。也就是描述符的一个对象
def __init__(self,n):
self.x=n #x的属性被描述符代理,通通触发Foo的set方法
b1=Bar(10)
#b1.x #另外一个类产生的实例,一调用x的属性,也就是foo的一个实例。就触发了描述符的get方法
b1.x=2
b1.y=22
print(b1.__dict__) >>>
set方法 10
<__main__.Bar object at 0x10207e780>
set方法 2
<__main__.Bar object at 0x10207e780>
{'x': 2, 'y': 22}

4 注意事项:
一 描述符本身应该定义成新式类,被代理的类也应该是新式类
二 必须把描述符定义成另外一个类的类属性,不能为定义到构造函数中
三 要严格遵循该优先级,优先级由高到底分别是
1.类属性   Bar.x  操作的是自己的属性字典,和数据属性统一级别,存在更新覆盖.
2.数据描述符
3.实例属性     b1.x  现在自己的属性字典里面找,找不到,再到类的属性字典里面找---找到的是X对应的Foo()的对象。自然调到描述符去了。
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 func(self):
print('我胡汉三又回来了') def __getattr__(self, item):
print('找不到了当然是来找我啦',item)
f1=Foo() f1.xxxxxxxxxxx

非数据描述符>找不到

5 描述符使用

day28

6、软件开发规范

总结:

#自省
hasattr(obj,'属性') #obj.属性 是否存在
getattr(obj,'属性') #获取obj.属性 不存在则报错
getattr(obj,'属性','默认值') #获取obj.属性 不存在不会报错,返回那个默认值
setattr(obj,'属性','属性的值') #obj.属性=属性的值
delattr(obj,'属性') #del obj.属性

#__getattr__,__setattr__,__delattr__
obj点的方式去操作属性时触发的方法

__getattr__:obj.属性 不存在时触发
__setattr__:obj.属性=属性的值 时触发
__delattr__:del obj.属性 时触发

#__getitem__,__setitem_,__delitem__
obj[‘属性’]的方式去操作属性时触发的方法

__getitem__:obj['属性'] 时触发
__setitem__:obj['属性']=属性的值 时触发
__delitem__:del obj['属性'] 时触发

#__get__,__set__,__delete__
描述就是一个新式类,这个类至少要实现上述三个方法的一个
class 描述符:
def __get__():
pass
def __set__():
pass
def __delete__():
pass

class 类:
name=描述符()

obj=类()
obj.name #get
obj.name='egon' #set
del obj.name #delete

#__del__:析构方法
垃圾回收时触发

最新文章

  1. RIDE -- Robot Framework setup
  2. tornado学习笔记19 Tornado框架分析
  3. android 入门-android自定义控件
  4. DAO接口及实现类
  5. Java获取、删除文件和目录
  6. 样条曲线的Fortran程序
  7. 为什么我们使用192.168.0.1作为内网ip
  8. LeetCode Number of Islands 岛的数量(DFS,BFS)
  9. 小白日记32:kali渗透测试之Web渗透-扫描工具-QWASP_ZAP
  10. IEnumerable和IEnumerator 详解
  11. ZOJ 3471 压缩状态DP
  12. CSS样式鼠标点击与经过的效果一样
  13. scanf和gets的差别
  14. Android安全开发之WebView中的大坑
  15. rcnn fast-rcnn faster-rcnn资料
  16. 广州站长沙龙 MIP 问题及答案
  17. java-数组排序--冒泡排序、鸡尾酒排序、地精排序
  18. asp.net core参数保护之自定义要保护的参数类型
  19. laravel学习笔记二
  20. python之MRO和垃圾回收机制

热门文章

  1. IE7下如何判断复选框是否被选中(利用jquery)
  2. LeetCode 094 Binary Tree Inorder Traversal
  3. POJ2653判断直线是否相交
  4. 混合开发H5的图片怎么适配自己想要的大小
  5. iOS—Mask属性的使用
  6. 传智播客JavaWeb day10-jdbc操作mysql、连接数据库六大步骤
  7. rsync一些安全的使用方法
  8. html中的空格显示问题
  9. jquery .attr()
  10. 《Web全栈工程师的自我修养》读书笔记(转载)