一、描述符是什么
描述符本质就是一个新式类,在这个新式类中,至少实现了__get__()
,__set__()
,__delete__()
中的一个,这也被称为描述符协议
__get__()
:调用一个属性时,触发
__set__()
:为一个属性赋值时,触发
__delete__()
:采用del删除属性时,触发
1 2 3 4 5 6 7
| class Foo: def __get__(self, instance, owner): print('__get__(),被执行了') def __set__(self, instance, value): print('__set__(),被执行了') def __delete__(self, instance): print('__delete__(),被执行了')
|
二、描述符的作用
描述符的作用是用来代理另外一个类的属性的(必须把描述符定义成这个类的类属性,不能定义到构造函数中)
1 2 3 4 5 6 7
| class Test: x = Foo() def __init__(self,x): self.x = x
t = Test(2) print(t.x)
|
三、描述符分为两种
1、数据描述符:至少实现了__get__()
和__set__()
2、非数据描述符:没有实现__set__()
1 2 3 4 5 6 7 8 9 10 11
| class Foo: def __set__(self, instance, value): print('set') def __get__(self, instance, owner): print('get')
class Foo: def __get__(self, instance, owner): print('get')
|
四、注意事项:
描述符本身应该定义成新式类,被代理的类也应该是新式类
必须把描述符定义成这个类的类属性,不能为定义到构造函数中
要严格遵循该优先级,优先级由高到底分别是
1类属性
2数据描述符
3实例属性
4非数据描述符
5找不到的属性触发__getattr__()
五、描述符的应用
1、现在有一个需求,定义一个用户信息,用户的名字为字符串类型,年龄为int类型,收入为float类型,可以用描述符来代理这些属性,从而控制传入的数据类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| class DescType:
def __get__(self, instance, owner): print('\n执行了__get__') print('self是 %s' % self) print('instance是 %s' % instance) print('owner是 %s' % owner)
def __set__(self, instance, value): print('\n执行了__set__') print('self是 %s' % self) print('instance是 %s' % instance) print('value是 %s' % value)
def __delete__(self, instance): print('\n执行了__delete__') print('instance是 %s' % instance)
class People: name = DescType()
def __init__(self, name, age, salary): self.name = name self.age = age self.salary = salary
p1 = People('Loney', 24, 11.1) print(p1.name) print(p1.__dict__)
|
发现被代理的name属性并没有被设置对应的值,所以__dict__
中没有’name’,那是因为实例化的时候执行了__init__
,所以也执行了__set__
, 但是在__set__
中并没有真正的操作进行设置。
2、所以要想真正的对属性进行代理,对属性进行设置、获取和删除值,则需要通过操作底层__dict__
字典,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| class DescType: def __init__(self, key, value_type): print('描述符初始化... key:', key, ' value_type:', value_type) self.key = key self.value_type = value_type
def __get__(self, instance, owner): print('执行了__get__') return instance.__dict__[self.key]
def __set__(self, instance, value): print('\n执行了__set__') print('self是 %s' % self) print('instance是 %s' % instance) print('value是 %s' % value) print('value_type %s' % self.value_type) if not isinstance(value, self.value_type): raise TypeError('%s 传入的不是 %s' % (self.key, self.value_type)) instance.__dict__[self.key] = value
def __delete__(self, instance): print('执行了__delete__') instance.__dict__.pop(self.key)
class People: name = DescType('name', str) age = DescType('age', int) salary = DescType('salary', float)
def __init__(self, name, age, salary): self.name = name self.age = age self.salary = salary
p2 = People('Loney', 24, 20.0)
print('*'*100) print(p2.name)
|
六、总结
1、描述符就是一个类(新式类);
2、描述符分为数据描述和非数据描述符,区别在于前者有__set__
方法,后者没有;
3、描述符的使用要遵循优先级:类属性>数据描述符>实例属性>非数据描述符>找不到(__getattr__
);
4、描述符方法中的self表示的是描述符实例化的对象,instance表示的是被描述(代理)的类实例化的对象,owner表示的是被描述(代理)的类,value表示的是设置到被描述(代理)属性的值。
以上。
– end –