描述符的应用
1、本来name应该是传字符串,age传数字,salary是传浮点数,但是我瞎传也可以,说明python没有帮我们判断这个类型
class People: def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary p1=People("gouguoqi",28,30000.0) p2=People(222,"28",30000.0)
2、那我们用学过的描述符来判断一下类型
class Typed:#定义一个描述符Typed def __get__(self, instance, owner):#描述符必须要有get set delelte print("get方法") print("get instance参数[%s]" %instance) print("get ower参数[%s]" %owner) def __set__(self, instance, value): print("set方法") print("set instance参数[%s]" % instance) print("set value参数[%s]" % value) def __delete__(self, instance): print("de instance参数[%s]" % instance) class People: name=Typed()#描述符 def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary p1=People("gouguoqi",28,30000.0) C:\python35\python3.exe D:/pyproject/day30/描述符的应用.py set方法 set instance参数[<__main__.People object at 0x00000000006D4588>] set value参数[gouguoqi]
实例化的过程就是触发__init__然后赋值给name,就触发了__set__方法,
3、查看一下p1的属性字典,发现没有name。因为name被代理了,是一个Peopele的数据描述符
class Typed:#定义一个描述符Typed def __get__(self, instance, owner):#描述符必须要有get set delelte print("get方法") print("get instance参数[%s]" %instance) print("get ower参数[%s]" %owner) def __set__(self, instance, value): print("set方法") print("set instance参数[%s]" % instance) print("set value参数[%s]" % value) def __delete__(self, instance): print("de instance参数[%s]" % instance) class People: name=Typed() def __init__(self,name,age,salary): self.name=name#这里触发的是Typed的set方法 self.age=age self.salary=salary p1=People("gouguoqi",28,30000.0) p1.name#调用实例p1的name属性,会触发描述符的get方法 print(p1.__dict__) C:\python35\python3.exe D:/pyproject/day30/描述符的应用.py set方法 set instance参数[<__main__.People object at 0x00000000006D4588>] set value参数[gouguoqi] get方法 get instance参数[<__main__.People object at 0x0000000000D44588>] get ower参数[<class '__main__.People'>] {'age': 28, 'salary': 30000.0}
4、实现真正意义的赋值和调用和删除,并存入实例的属性字典
class Typed:#定义一个描述符Typed def __init__(self,key): self.key=key def __get__(self, instance, owner):#描述符必须要有get set delelte print("get方法") return instance.__dict__[self.key] def __set__(self, instance, value): print("set方法") instance.__dict__[self.key]=value def __delete__(self, instance): print("de instance参数[%s]" % instance) instance.__dict__.pop(self.key) class People: name=Typed("name") def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary p1=People("gouguoqi",28,30000.0) print(p1.__dict__) print(p1.name)#调用实例p1的name属性,会触发描述符的get方法 C:\python35\python3.exe D:/pyproject/day30/描述符的应用.py set方法 {'age': 28, 'name': 'gouguoqi', 'salary': 30000.0} get方法 gouguoqi
5、试试修改一下名字的值
class Typed:#定义一个描述符Typed def __init__(self,key): self.key=key def __get__(self, instance, owner):#描述符必须要有get set delelte print("get方法") # print("get instance参数[%s]" %instance) # print("get ower参数[%s]" %owner) return instance.__dict__[self.key] def __set__(self, instance, value): print("set方法") # print("set instance参数[%s]" % instance) # print("set value参数[%s]" % value) instance.__dict__[self.key]=value def __delete__(self, instance): print("de instance参数[%s]" % instance) instance.__dict__.pop(self.key) class People: name=Typed("name") # age = Typed("age") def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary p1=People("gouguoqi",28,30000.0) print(p1.__dict__)#打印属性字典 p1.name="sb"#赋值给给实例的name属性的值,触发set print(p1.name)#调用实例p1的name属性,会触发描述符的get方法 C:\python35\python3.exe D:/pyproject/day30/描述符的应用.py set方法 {'name': 'gouguoqi', 'salary': 30000.0, 'age': 28} set方法 get方法 sb
6、删除一下试试
class Typed:#定义一个描述符Typed def __init__(self,key): self.key=key def __get__(self, instance, owner):#描述符必须要有get set delelte print("get方法") # print("get instance参数[%s]" %instance) # print("get ower参数[%s]" %owner) return instance.__dict__[self.key] def __set__(self, instance, value): print("set方法") # print("set instance参数[%s]" % instance) # print("set value参数[%s]" % value) instance.__dict__[self.key]=value def __delete__(self, instance): # print("de instance参数[%s]" % instance) instance.__dict__.pop(self.key) class People: name=Typed("name") # age = Typed("age") def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary p1=People("gouguoqi",28,30000.0) print(p1.__dict__)#打印属性字典 del p1.name #删除实例的name属性 会触发Typed的delete方法 print(p1.__dict__)#再次查看属性字典 C:\python35\python3.exe D:/pyproject/day30/描述符的应用.py set方法 {'name': 'gouguoqi', 'salary': 30000.0, 'age': 28} {'salary': 30000.0, 'age': 28}
7、加一个判断,如果name传入的值不是字符串的话就raise一个错误
(1)传入的是字符串的时候,一切正常
class Typed:#定义一个描述符Typed def __init__(self,key): self.key=key def __get__(self, instance, owner):#描述符必须要有get set delelte print("get方法") # print("get instance参数[%s]" %instance) # print("get ower参数[%s]" %owner) return instance.__dict__[self.key] def __set__(self, instance, value): print("set方法") # print("set instance参数[%s]" % instance) # print("set value参数[%s]" % value) if not isinstance(value,str): # print("你传入的不是字符串") # return raise TypeError("你传入的不是字符串") instance.__dict__[self.key]=value def __delete__(self, instance): # print("de instance参数[%s]" % instance) instance.__dict__.pop(self.key) class People: name=Typed("name") # age = Typed("age") def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary p1=People("gouguoqi",28,30000.0) print(p1.__dict__)#打印属性字典 C:\python35\python3.exe D:/pyproject/day30/描述符的应用.py set方法 {'salary': 30000.0, 'name': 'gouguoqi', 'age': 28}
(2)传入的name不是字符串的时候
class Typed:#定义一个描述符Typed def __init__(self,key): self.key=key def __get__(self, instance, owner):#描述符必须要有get set delelte print("get方法") # print("get instance参数[%s]" %instance) # print("get ower参数[%s]" %owner) return instance.__dict__[self.key] def __set__(self, instance, value): print("set方法") # print("set instance参数[%s]" % instance) # print("set value参数[%s]" % value) if not isinstance(value,str): # print("你传入的不是字符串") # return raise TypeError("你传入的不是字符串") instance.__dict__[self.key]=value def __delete__(self, instance): # print("de instance参数[%s]" % instance) instance.__dict__.pop(self.key) class People: name=Typed("name") # age = Typed("age") def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary p2=People(222,28,30000.0) File "D:/pyproject/day30/描述符的应用.py", line 22, in __set__ raise TypeError("你传入的不是字符串") TypeError: 你传入的不是字符串
8、我们现在实现了判断name的值是不是字符串,那么怎么来控制age必须是数字呢,现在的情况是我们age这里也必须得传入字符串才能正常运行
class Typed:#定义一个描述符Typed def __init__(self,key): self.key=key def __get__(self, instance, owner):#描述符必须要有get set delelte print("get方法") # print("get instance参数[%s]" %instance) # print("get ower参数[%s]" %owner) return instance.__dict__[self.key] def __set__(self, instance, value): print("set方法") if not isinstance(value,str): # print("你传入的不是字符串") # return raise TypeError("你传入的不是字符串") instance.__dict__[self.key]=value def __delete__(self, instance): # print("de instance参数[%s]" % instance) instance.__dict__.pop(self.key) class People: name=Typed("name") age=Typed("age") def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary p2=People("gouguoqi","28",30000.0) print(p2.age) C:\python35\python3.exe D:/pyproject/day30/描述符的应用.py set方法 set方法 get方法 28
那么应该怎么做呢,现在的问题就是,你判断的东西必须全部是字符串,是别的就会报错,这是写死了呀,那么如何写活呢
我们可以在复制一个Typed为Type1把判断条件改为int就行了
class Typed:#定义一个描述符Typed def __init__(self,key): self.key=key def __get__(self, instance, owner):#描述符必须要有get set delelte print("get方法") return instance.__dict__[self.key] def __set__(self, instance, value): print("set方法") if not isinstance(value,str): raise TypeError("你传入的不是字符串") instance.__dict__[self.key]=value def __delete__(self, instance): instance.__dict__.pop(self.key) class Typed1:#定义一个描述符Typed def __init__(self,key): self.key=key def __get__(self, instance, owner):#描述符必须要有get set delelte print("get方法") return instance.__dict__[self.key] def __set__(self, instance, value): print("set方法") if not isinstance(value,int): raise TypeError("你传入的不是数字") instance.__dict__[self.key]=value def __delete__(self, instance): instance.__dict__.pop(self.key) class People: name=Typed("name") age=Typed1("age") def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary p2=People("gouguoqi","28",30000.0) TypeError: 你传入的不是数字
当我们age字段传入的参数是数字的时候就可以正常运行了,但是这样又是重复代码了呀
最终版本
class Typed:#定义一个描述符Typed def __init__(self,key,expec_type): self.key=key self.expec_type=expec_type def __get__(self, instance, owner):#描述符必须要有get set delelte print("get方法") return instance.__dict__[self.key] def __set__(self, instance, value): print("set方法") if not isinstance(value,self.expec_type): raise TypeError("%s你传入的不是%s" %(self.key,self.expec_type)) instance.__dict__[self.key]=value def __delete__(self, instance): instance.__dict__.pop(self.key) class People: name=Typed("name",str) age=Typed("age",int) def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary p2=People("gouguoqi","28",30000.0) TypeError: age你传入的不是<class 'int'>