描述符 __set__(),__get__(),__delete__()
1 class Str: 2 def __set__(self, instance, value): 3 print("Str_set",instance,value) 4 print(id(instance)) #instance 是 Person() 的实例对象 5 6 7 def __get__(self, instance, owner): 8 print("Str_get") 9 10 def __delete__(self, instance): 11 print("Str_delete") 12 13 class Person: 14 name = Str() 15 def __init__(self,name): 16 self.name = name 17 18 if __name__ == "__main__": 19 p = Person("tom") 20 print(id(p)) 21 ''' 22 Str_set <__main__.Person object at 0x00000194CA51B0F0> tom 23 1738561138928 24 1738561138928 25 '''
优先级:类属性> 数据描述符(必有set)>实例属性>非数据描述符(只有get)>找不到
类属性>数据>实例
1 class Str: 2 def __set__(self, instance, value): 3 print("Str_set") 4 5 def __get__(self, instance, owner): 6 print("Str_get") 7 8 def __delete__(self, instance): 9 print("Str_delete") 10 11 class Person: 12 name = Str() 13 def __init__(self,name): 14 self.name = name 15 16 if __name__ == "__main__": #有set 和delete 的是数据描述符 反之是非数据(只有get) 17 p = Person("tom") #因为实例小于数据描述符 数据描述符起作用 18 #Person.name = "tom" # 类属性的优先级高于数据描述符 数据描述符不起作用 19 #del Person.name #类属性优先级高于数据描述符 数据描述符不起作用 20 # Person.name #类属性字典中没有 数据描述符起作用 21 22 p.name = "tom" #实例小于数据描述符 数据描述符起作用 23 del p.name #实例小于数据描述符 数据描述符起作用 24 p.name #实例小于数据描述符 数据描述符起作用
实例>非数据>找不到
1 class Str: 2 # def __set__(self, instance, value): 3 # print("Str_set") 4 5 def __get__(self, instance, owner): 6 print("Str_get") 7 # 8 # def __delete__(self, instance): 9 # print("Str_delete") 10 11 class Person: 12 name = Str() 13 def __init__(self,name): 14 self.name = name 15 16 if __name__ == "__main__": 17 p = Person("tom") #因为实例大于非数据描述符 数据描述符不起作用 18 19 p.name = "jack" #因为实例大于非数据描述符 数据描述符不起作用 20 p.name #因为实例大于非数据描述符 数据描述符不起作用 21 del p.name #因为实例大于非数据描述符 数据描述符不起作用 22 #================================ 23 24 p.name #此时非数据描述符大于找不到,就起作用了 25 ''' 26 输出: 27 28 Str_get 29 '''
描述符的应用:
众所周知,Python是弱类型的语言,即参数的赋值没有类型的限制,下面通过描述符的机制实现类型限制功能。
1 class Person: 2 def __init__(self,name,age,salary): 3 self.name = name 4 self.age = age 5 self.salary = salary 6 7 if __name__ =="__main__": 8 p1 = Person("tom",18,100) 9 p2 = Person(108,"tom","jack") #程序是不会报错的,需求就是让它做类型检测
1 class Check: 2 def __init__(self,key): 3 self.key = key 4 5 def __set__(self, instance, value): 6 print("set") 7 if isinstance(value,str): 8 instance.__dict__[self.key] = value 9 else: 10 print("{}输入有误".format(self.key)) 11 def __get__(self, instance, owner): 12 print("get") 13 return instance.__dict__[self.key] 14 15 def __delete__(self, instance): 16 print("delete") 17 instance.__dict__.pop(self.key) 18 19 class Person: 20 name = Check("name") #传入“name” 方便操作Person实例对象的属性字典 21 def __init__(self,name,age,salary): 22 self.name = name 23 self.age = age 24 self.salary = salary 25 26 if __name__ =="__main__": 27 p1 = Person("tom",18,100) 28 p2 = Person(108,"tom","jack") 29 ''' 30 输出: 31 set 32 set 33 name输入有误 34 '''
改进一:
1 class Check: 2 def __init__(self,key): 3 self.key = key 4 5 def __set__(self, instance, value): 6 print("set") 7 if isinstance(value,str): 8 instance.__dict__[self.key] = value 9 else: 10 raise TypeError("{}输入有误".format(self.key)) #这样如果有误直接就将程序停止了 11 # print("{}输入有误".format(self.key)) 12 def __get__(self, instance, owner): 13 print("get") 14 return instance.__dict__[self.key] 15 16 def __delete__(self, instance): 17 print("delete") 18 instance.__dict__.pop(self.key) 19 20 class Person: 21 name = Check("name") #传入“name” 方便操作Person实例对象的属性字典 22 def __init__(self,name,age,salary): 23 self.name = name 24 self.age = age 25 self.salary = salary 26 27 if __name__ =="__main__": 28 p1 = Person("tom",18,100) 29 p2 = Person(108,"tom","jack")
终极版:
class Check: def __init__(self,key,type): self.key = key self.type= type def __set__(self, instance, value): print("set") if isinstance(value,self.type): instance.__dict__[self.key] = value else: print("{}输入有误".format(self.key)) # raise TypeError("{}输入有误".format(self.key)) def __get__(self, instance, owner): print("get") return instance.__dict__[self.key] def __delete__(self, instance): print("delete") instance.__dict__.pop(self.key) class Person: name = Check("name",str) age = Check("age",int) salary = Check("salary",float) def __init__(self,name,age,salary): self.name = name self.age = age self.salary = salary if __name__ =="__main__": p1 = Person("tom",18,100.0) print("============") p2 = Person(108,"tom","jack") ''' set set set ============ set name输入有误 set age输入有误 set salary输入有误 '''
这就是描述符的应用!