# 描述符 __get__ __set__ delete__ # 描述符本质就是一个新式类,在这个新式类中,至少实现了__get__(),__set__(),__delete()中的一个,这也称为描述符协议 # __get__() 调用一个属性时触发 # __set__() 为一个属性赋值时触发 # __delete__() 使用del删除属性时触发 # 描述符的作用是用来代理另外一个类的属性(必须把描述符定义成这个类的类属性,不能定义到构造函数中) # 描述符分为两种:1、数据描述符:至少实现了__get__和__set__; 2、非数据描述符:没有实现__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的实例赋值给x b1 = Bar() b1.x # get,此时触发了Foo类中的__get__方法 b1.x = 1 # set,此时触发了Foo类中的__set__方法 del b1.x # delete,此时触发了Foo类中的__delete__方法 # 描述符的优先级 # 1 类属性 # 2 数据描述符 # 3 实例属性 # 4 非数据描述符 # 5 找不到的属性触发__getattr__()
# 使用描述符为python加上类型检测功能 class Typed: # 定义描述符的类,必须是一个数据描述符 def __init__(self, key, expected_type): # 定义一个实例化方法,主要用于传实例字典的key,和期望的数据类型 self.key = key self.expected_type = expected_type def __get__(self, instance, owner): # instance 代表实例(p1) owener代表实例的拥有者(People) return instance.__dict__[self.key] # 返回实例字典key的值 def __set__(self, instance, value): # instance 代表实例(p1) value代表传入的值 if not isinstance(value, self.expected_type): # 判断用户传入的name如果不是字符串 print('你传入的类型不是%s' % self.expected_type) return # return终止此方法,不执行下面的赋值 instance.__dict__[self.key] = value class People: name = Typed('name', str) # 传key值到描述符的__init__中 age = Typed('age', int) salary = Typed('salary', float) def __init__(self, name, age, salary): self.name = name self.age = age self.salary = salary p1 = People('alex', 18, 2584.25) print(p1.__dict__) # {'name': 'alex', 'age': 18, 'salary': 2584.25} p1.name = 'egon' print(p1.__dict__) # {'name': 'egon', 'age': 18, 'salary': 2584.25}