描述符
描述符(__get__,__set__,__delete__) # 这里着重描述了python的底层实现原理
1、 描述符是什么:描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete__()中的一个,这也被称为描述符协议。
__get__():调用一个属性时,触发
__set__():为一个属性赋值时,触发
__delete__():采用del删除属性时,触发
1 class Foo: #在python3中Foo是新式类,它实现了三种方法,这个类就被称作一个描述符 2 def __get__(self,instance,owner): 3 print(\'get方法\') 4 def __set__(self, instance, value): 5 print(\'set方法\') 6 def __delete__(self, instance): 7 print(\'delete方法\')
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\' print(f1.name) del f1.name #疑问:何时,何地,会触发这三个方法的执行
3、描述符应用在什么时候,什么地方
class D: def __get__(self, instance, owner): print("-->get") def __set__(self, instance, value): print("-->set") def __delete__(self, instance): print("-->delete") class E: e = D() # 描述谁? ee = E() ee.y = 10 # 此时描述的是e y则不会被描述 ee.e # 访问e属性,则会触发__get__ ee.e = 2 # 为e进行赋值操作,则会触发__set__ del ee.e # 删除e的属性,则会触发__delete__ # print(ee.__dict__)
4、描述符分为俩种形式。
a.数据描述符(至少实现了__get__()和__set__()两种方法)
class Foo: def __set__(self, instance, value): print(\'set\') def __get__(self, instance, owner): print(\'get\')
b.非数据描述符(没有实现__set__()方法)
1 class Foo: 2 def __get__(self, instance, owner): 3 print(\'get\')
注意事项:
一、描述符本身应该定义成新式类,被代理的类也应该是新式类
二、必须把描述符定义成另外一个类触发的类属性,不能为定义到构造函数
5、严格遵循描述符的优先级别,由高到低
a.类属性—》b.数据数据描述符—》c.实例属性—》d.非数据描述符—》e.找不到的属性触发__getattr__()
1 class Foo: 2 def __get__(self,instance,owner): 3 print(\'===>get方法\') 4 def __set__(self, instance, value): 5 print(\'===>set方法\') 6 def __delete__(self, instance): 7 print(\'===>delete方法\') 8 9 class Bar: 10 x=Foo() #调用foo()属性,会触发get方法 11 12 print(Bar.x) #类属性比描述符有更高的优先级,会触发get方法 13 Bar.x=1 #自己定义了一个类属性,并赋值给x,跟描述符没有关系,所以不会触发描述符的方法 14 # print(Bar.__dict__) 15 print(Bar.x) 16 17 18 ===>get方法 19 None 20 1
#有get,set就是数据描述符,数据描述符比实例属性有更高的优化级 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() # 调用foo()属性,会触发get方法 b1=Bar() #在自己的属性字典里面找,找不到就去类里面找,会触发__get__方法 b1.x #调用一个属性的时候触发get方法 b1.x=1 #为一个属性赋值的时候触发set方法 del b1.x #采用del删除属性时触发delete方法 ===>get方法 ===>set方法 ===>delete方法
1 #类属性>数据描述符>实例属性 2 3 class Foo: 4 def __get__(self,instance,owner): 5 print(\'===>get方法\') 6 def __set__(self, instance, value): 7 print(\'===>set方法\') 8 def __delete__(self, instance): 9 print(\'===>delete方法\') 10 11 class Bar: 12 x = Foo() #调用foo()属性,会触发get方法 13 14 b1=Bar() #实例化 15 Bar.x=11111111111111111 #不会触发get方法 16 b1.x #会触发get方法 17 18 del Bar.x #已经给删除,所以调用不了!报错:AttributeError: \'Bar\' object has no attribute \'x\' 19 b1.x
#实例属性>非数据描述符 class Foo: def __get__(self,instance,owner): print(\'===>get方法\') class Bar: x = Foo() b1=Bar() b1.x=1 print(b1.__dict__) #在自己的属性字典里面,{\'x\': 1} {\'x\': 1}
1 #非数据描述符>找不到 2 3 class Foo: 4 def __get__(self,instance,owner): 5 print(\'===>get方法\') 6 7 class Bar: 8 x = Foo() 9 def __getattr__(self, item): 10 print(\'------------>\') 11 12 b1=Bar() 13 b1.xxxxxxxxxxxxxxxxxxx #调用没有的xxxxxxx,就会触发__getattr__方法 14 15 16 ------------> #解发__getattr__方法
6、关于描述符的应用(类型检测的应用)
class Typed: def __get__(self, instance,owner): print(\'get方法\') print(\'instance参数【%s】\' %instance) print(\'owner参数【%s】\' %owner) # owner是显示对象是属于谁拥有的 def __set__(self, instance, value): print(\'set方法\') print(\'instance参数【%s】\' %instance) # instance是被描述类的对象(实例) print(\'value参数【%s】\' %value) # value是被描述的值 def __delete__(self, instance): print(\'delete方法\') print(\'instance参数【%s】\'% instance) class People: name=Typed() def __init__(self,name,age,salary): self.name=name #触发的是代理 self.age=age self.salary=salary p1=People(\'alex\',13,13.3) #\'alex\' #触发set方法 p1.name #触发get方法,没有返回值 p1.name=\'age\' #触发set方法 python 描述符 上下文管理协议 类装饰器 property metaclassPython - 元类装饰器 - 如何使用 @classmethod