一、概念:
Python 中,通过使用描述符,可以让程序在引用一个对象属性时自定义要完成的工作。
本质上看,描述符就是一个类,只不过它定义了另一个类中属性的访问方式。
换句话说,一个类可以将属性全权委托给描述符类。
描述符类基于以下3个特殊方法:
♦ __set__ (self, instance, value) 设置属性调用
♦ __get__(self,instance, owner) 访问属性调用
♦ __delete__(self, instance) 对属性调用del 时将调用这一方法
二、描述符分两种
①数据描述符:至少实现了 __get__()和__set__()
class Foo: def __set__(selfsself,instance, value): print("set") def __get__(self, instance, owner): print("get")
②非数据描述符:没有实现__set__()
class Foo: def __get__(self, instance, owner): print("get")
实例:
class Foo: def __get__(self, instance, owner): #这里的instance是实例对象b1,owner是类Bar print("===>get方法") return instance.__dict__['x'] def __set__(self, instance, value): #这里的instance是实例对象b1,value是传入的值 print("===>set方法") instance.__dict__['x'] = value def __delete__(self, instance): print("===>delete方法") instance.__dict__.pop('x') class Bar: x = Foo() #将x 全权给Foo类代理,此时 x 就是描述符 def __init__(self, n): self.x = n b1 = Bar(10) print(b1.__dict__) print(b1.x) del b1.x print(b1.__dict__) b1.x = 222222222 print(b1.__dict__) b1.y = 2222 print(b1.__dict__)
三、描述符优先级
类属性 > 数据描述符 > 实例属性 > 非数据属性 > 找不到的属性触发__getattr__
class Foo: def __get__(self, instance, owner): #这里的instance是实例对象b1,owner是类Bar print("===>get方法") # return instance.__dict__['x'] def __set__(self, instance, value): #这里的instance是实例对象b1,value是传入的值 print("===>set方法") # instance.__dict__['x'] = value def __delete__(self, instance): print("===>delete方法") # instance.__dict__.pop('x') class Bar: x = Foo() def __init__(self, n): self.x = n b1 = Bar(10) print(Bar.__dict__) #这里打印字典看出:x 是一个对象 Bar.x = 10 print(Bar.x) print(Bar.__dict__) #当Bar.x为x后,直接覆盖了描述符的操作
class Foo: def __get__(self, instance, owner): #这里的instance是实例对象b1,owner是类Bar print("===>get方法") # return instance.__dict__['x'] def __set__(self, instance, value): #这里的instance是实例对象b1,value是传入的值 print("===>set方法") # instance.__dict__['x'] = value def __delete__(self, instance): print("===>delete方法") # instance.__dict__.pop('x') class Bar: x = Foo() def __init__(self, n): self.x = n b1 = Bar(10) b1.x = 10 #可以看出。用实例为变量赋值时,直接触发数据描述符 print(b1.__dict__)
class Foo: def __get__(self, instance, owner): #这里的instance是实例对象b1,owner是类Bar print("===>get方法") # return instance.__dict__['x'] # def __set__(self, instance, value): #这里的instance是实例对象b1,value是传入的值 # print("===>set方法") # # instance.__dict__['x'] = value # def __delete__(self, instance): print("===>delete方法") # instance.__dict__.pop('x') class Bar: x = Foo() def __init__(self, n): self.x = n b1 = Bar(10) b1.x = 10 #可以看出。用实例为变量赋值时,没有触发非数据描述符 print(b1.__dict__)
class Foo: def __get__(self, instance, owner): #这里的instance是实例对象b1,owner是类Bar print("===>get方法") # return instance.__dict__['x'] # def __set__(self, instance, value): #这里的instance是实例对象b1,value是传入的值 # print("===>set方法") # # instance.__dict__['x'] = value # def __delete__(self, instance): print("===>delete方法") # instance.__dict__.pop('x') class Bar: x = Foo() def __init__(self, n): self.x = n def __getattr__(self, item): print("qaq") b1 = Bar(10) b1.yyyy #当查找的属性不存在时