python(描述符应用与类的装饰器)
__enter__和__exit__
数据描述符:至少实现__get__,__set__方法的
非数据描述符:没有__set__方法的
上下文管理协议(with语句)改写,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法。
# -*- coding: utf-8 -*- class Open: def __init__(self,name): self.name=name def __enter__(self): print(‘出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量‘) # return self def __exit__(self, exc_type, exc_val, exc_tb): print(‘with中代码块执行完毕时执行我啊‘) with Open(‘b.txt‘) as f: print(‘=====>执行代码块‘) # print(f,f.name)
# -*- coding: utf-8 -*- class Open: def __init__(self,name): self.name=name def __enter__(self): print(‘出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量‘) def __exit__(self, exc_type, exc_val, exc_tb): print(‘with中代码块执行完毕时执行我啊‘) #下面三个ext执行完毕就代表with代码块里的语句执行完毕,出现异常,下面的代码不再执行 print(exc_type) #异常类型 print(exc_val) #异常值 print(exc_tb) #追溯信息 with Open(‘b.txt‘) as f: #触发__enter__ print(‘=====>执行代码块‘) raise AttributeError(‘***着火啦,救火啊***‘) print(‘0‘*100) #------->不会执行
用途:
1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预
2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制
描述符应用
控制输入类型
# -*- coding: utf-8 -*- class Typed: def __init__(self,key): self.key=key def __get__(self,instance,owner): print(‘get方法‘) # print(‘isinstance参数;‘,isinstance) # print(‘owner参数;‘,owner) return instance.__dict__[self.key] def __set__(self,instance,value): print(‘set方法‘) # print(‘isinstance参数;‘,instance) # print(‘owner参数;‘,value) #通过初始化函数写活了 if not isinstance(value,str): print(‘输入不是字符串‘) else: instance.__dict__[self.key]=value def __delete__(self,instance): print(‘delete方法‘) # print(‘isinstance参数;‘, 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("bob",22,5000) p1.name print(p1.__dict__) #没有name属性,他被数据描述符代理了 del p1.name print(p1.__dict__) p2=people(1,22,5000)
进一步改进
# -*- coding: utf-8 -*- class Typed: def __init__(self,key,expected_type): self.key=key self.expected_type=expected_type def __get__(self,instance,owner): # print(‘get方法‘) # print(‘isinstance参数;‘,isinstance) # print(‘owner参数;‘,owner) return instance.__dict__[self.key] def __set__(self,instance,value): # print(‘set方法‘) # print(‘isinstance参数;‘,instance) # print(‘owner参数;‘,value) #通过初始化函数写活了 if not isinstance(value,self.expected_type): print(‘输入不是%s‘%self.expected_type) else: instance.__dict__[self.key]=value def __delete__(self,instance): print(‘delete方法‘) # print(‘isinstance参数;‘, instance) instance.__dict__.pop(self.key) class people: name=Typed(‘name‘,str) 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("bob",22,5000.0) p1.name print(p1.__dict__) #没有name属性,他被数据描述符代理了 del p1.name print(p1.__dict__) p2=people(1,22,5000.0)
类的装饰器
初级(没有参数):
# -*- coding: utf-8 -*- def decorate(cls): print(‘类的装饰器开始运行啦------>‘) return cls @decorate #无参:People=decorate(People) class People: def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary print(self.age,self.name,self.salary) p1=People(‘egon‘,18,3333.3)
------------恢复内容开始------------
__enter__和__exit__
数据描述符:至少实现__get__,__set__方法的
非数据描述符:没有__set__方法的
上下文管理协议(with语句)改写,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法。
# -*- coding: utf-8 -*- class Open: def __init__(self,name): self.name=name def __enter__(self): print(‘出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量‘) # return self def __exit__(self, exc_type, exc_val, exc_tb): print(‘with中代码块执行完毕时执行我啊‘) with Open(‘b.txt‘) as f: print(‘=====>执行代码块‘) # print(f,f.name)
# -*- coding: utf-8 -*- class Open: def __init__(self,name): self.name=name def __enter__(self): print(‘出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量‘) def __exit__(self, exc_type, exc_val, exc_tb): print(‘with中代码块执行完毕时执行我啊‘) #下面三个ext执行完毕就代表with代码块里的语句执行完毕,出现异常,下面的代码不再执行 print(exc_type) #异常类型 print(exc_val) #异常值 print(exc_tb) #追溯信息 with Open(‘b.txt‘) as f: #触发__enter__ print(‘=====>执行代码块‘) raise AttributeError(‘***着火啦,救火啊***‘) print(‘0‘*100) #------->不会执行
用途:
1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预
2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制
描述符应用
控制输入类型
# -*- coding: utf-8 -*- class Typed: def __init__(self,key): self.key=key def __get__(self,instance,owner): print(‘get方法‘) # print(‘isinstance参数;‘,isinstance) # print(‘owner参数;‘,owner) return instance.__dict__[self.key] def __set__(self,instance,value): print(‘set方法‘) # print(‘isinstance参数;‘,instance) # print(‘owner参数;‘,value) #通过初始化函数写活了 if not isinstance(value,str): print(‘输入不是字符串‘) else: instance.__dict__[self.key]=value def __delete__(self,instance): print(‘delete方法‘) # print(‘isinstance参数;‘, 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("bob",22,5000) p1.name print(p1.__dict__) #没有name属性,他被数据描述符代理了 del p1.name print(p1.__dict__) p2=people(1,22,5000)
进一步改进
# -*- coding: utf-8 -*- class Typed: def __init__(self,key,expected_type): self.key=key self.expected_type=expected_type def __get__(self,instance,owner): # print(‘get方法‘) # print(‘isinstance参数;‘,isinstance) # print(‘owner参数;‘,owner) return instance.__dict__[self.key] def __set__(self,instance,value): # print(‘set方法‘) # print(‘isinstance参数;‘,instance) # print(‘owner参数;‘,value) #通过初始化函数写活了 if not isinstance(value,self.expected_type): print(‘输入不是%s‘%self.expected_type) else: instance.__dict__[self.key]=value def __delete__(self,instance): print(‘delete方法‘) # print(‘isinstance参数;‘, instance) instance.__dict__.pop(self.key) class people: name=Typed(‘name‘,str) 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("bob",22,5000.0) p1.name print(p1.__dict__) #没有name属性,他被数据描述符代理了 del p1.name print(p1.__dict__) p2=people(1,22,5000.0)
类的装饰器
初级(没有参数):
# -*- coding: utf-8 -*- def decorate(cls): print(‘类的装饰器开始运行啦------>‘) return cls @decorate #无参:People=decorate(People) class People: def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary print(self.age,self.name,self.salary) p1=People(‘egon‘,18,3333.3)
------------恢复内容开始------------
__enter__和__exit__
数据描述符:至少实现__get__,__set__方法的
非数据描述符:没有__set__方法的
上下文管理协议(with语句)改写,为了让一个对象兼容with语句,必须在这个对象的类中声明__enter__和__exit__方法。
# -*- coding: utf-8 -*- class Open: def __init__(self,name): self.name=name def __enter__(self): print(‘出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量‘) # return self def __exit__(self, exc_type, exc_val, exc_tb): print(‘with中代码块执行完毕时执行我啊‘) with Open(‘b.txt‘) as f: print(‘=====>执行代码块‘) # print(f,f.name)
# -*- coding: utf-8 -*- class Open: def __init__(self,name): self.name=name def __enter__(self): print(‘出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量‘) def __exit__(self, exc_type, exc_val, exc_tb): print(‘with中代码块执行完毕时执行我啊‘) #下面三个ext执行完毕就代表with代码块里的语句执行完毕,出现异常,下面的代码不再执行 print(exc_type) #异常类型 print(exc_val) #异常值 print(exc_tb) #追溯信息 with Open(‘b.txt‘) as f: #触发__enter__ print(‘=====>执行代码块‘) raise AttributeError(‘***着火啦,救火啊***‘) print(‘0‘*100) #------->不会执行
用途:
1.使用with语句的目的就是把代码块放入with中执行,with结束后,自动完成清理工作,无须手动干预
2.在需要管理一些资源比如文件,网络连接和锁的编程环境中,可以在__exit__中定制自动释放资源的机制
描述符应用
控制输入类型
# -*- coding: utf-8 -*- class Typed: def __init__(self,key): self.key=key def __get__(self,instance,owner): print(‘get方法‘) # print(‘isinstance参数;‘,isinstance) # print(‘owner参数;‘,owner) return instance.__dict__[self.key] def __set__(self,instance,value): print(‘set方法‘) # print(‘isinstance参数;‘,instance) # print(‘owner参数;‘,value) #通过初始化函数写活了 if not isinstance(value,str): print(‘输入不是字符串‘) else: instance.__dict__[self.key]=value def __delete__(self,instance): print(‘delete方法‘) # print(‘isinstance参数;‘, 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("bob",22,5000) p1.name print(p1.__dict__) #没有name属性,他被数据描述符代理了 del p1.name print(p1.__dict__) p2=people(1,22,5000)
进一步改进
# -*- coding: utf-8 -*- class Typed: def __init__(self,key,expected_type): self.key=key self.expected_type=expected_type def __get__(self,instance,owner): # print(‘get方法‘) # print(‘isinstance参数;‘,isinstance) # print(‘owner参数;‘,owner) return instance.__dict__[self.key] def __set__(self,instance,value): # print(‘set方法‘) # print(‘isinstance参数;‘,instance) # print(‘owner参数;‘,value) #通过初始化函数写活了 if not isinstance(value,self.expected_type): print(‘输入不是%s‘%self.expected_type) else: instance.__dict__[self.key]=value def __delete__(self,instance): print(‘delete方法‘) # print(‘isinstance参数;‘, instance) instance.__dict__.pop(self.key) class people: name=Typed(‘name‘,str) 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("bob",22,5000.0) p1.name print(p1.__dict__) #没有name属性,他被数据描述符代理了 del p1.name print(p1.__dict__) p2=people(1,22,5000.0)
类的装饰器
初级(没有参数):
# -*- coding: utf-8 -*- def decorate(cls): print(‘类的装饰器开始运行啦------>‘) return cls @decorate #无参:People=decorate(People) class People: def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary print(self.age,self.name,self.salary) p1=People(‘egon‘,18,3333.3)
进阶(有参数)
# -*- coding: utf-8 -*- def typeassert(**kwargs): def decorate(cls): print(‘2------>‘) for key,value in kwargs.items(): setattr(cls,key,value) return cls print(‘1------>‘, kwargs) return decorate @typeassert() #name=str,age=int,salary=float #有参:1.运行typeassert(...)返回结果是decorate,此时参数都传给kwargs 2.People=decorate(People) class People: pass # def __init__(self,name,age,salary): # self.name=name # self.age=age # self.salary=salary print(People.__dict__) @typeassert(hobby=‘ball‘) class bar(): pass#添加了hobby属性 print(bar.__dict__)
可添加不定个数属性的示例:
# -*- coding: utf-8 -*- class Typed: def __init__(self,name,expected_type): self.name=name self.expected_type=expected_type def __get__(self, instance, owner): print(‘get--->‘,instance,owner) if instance is None: return self return instance.__dict__[self.name] def __set__(self, instance, value): print(‘set--->‘,instance,value) if not isinstance(value,self.expected_type): raise TypeError(‘Expected %s‘ %str(self.expected_type)) instance.__dict__[self.name]=value def __delete__(self, instance): print(‘delete--->‘,instance) instance.__dict__.pop(self.name) def typeassert(**kwargs): def decorate(cls): print(‘类的装饰器开始运行啦------>‘,kwargs) for name,expected_type in kwargs.items(): setattr(cls,name,Typed(name,expected_type)) return cls return decorate @typeassert(name=str,age=int,salary=float)#在此添加要增加的属性 #有参:1.运行typeassert(...)返回结果是decorate,此时参数都传给kwargs 2.People=decorate(People) class People: def __init__(self,name,age,salary): self.name=name self.age=age self.salary=salary print(People.__dict__) p1=People(‘egon‘,18,3333.3)
自定制property
装饰器可以是函数,也可以是类类型。
# -*- coding: utf-8 -*- class Lazyproperty: def __init__(self,func): self.func=func def __get__(self, instance, owner): print(‘这是我们自己定制的静态属性,r1.area实际是要执行r1.area()‘) if instance is None: return self return self.func(instance) #此时你应该明白,到底是谁在为你做自动传递self的事情 class Room: def __init__(self,name,width,length): self.name=name self.width=width self.length=length @Lazyproperty #area=Lazyproperty(area) 相当于定义了一个类属性,即描述符 def area(self): return self.width * self.length r1=Room(‘alex‘,1,1) print(r1.area) #将r1.area传参数写在Lazyproperty中的__get__里
应用:自制property实现延迟计算功能
# -*- coding: utf-8 -*- class Lazyproperty: def __init__(self,func): self.func=func def __get__(self, instance, owner): print(‘这是我们自己定制的静态属性,r1.area实际是要执行r1.area()‘) if instance is None: return self else: print(‘--->‘) value=self.func(instance) setattr(instance,self.func.__name__,value) #计算一次就缓存到实例的属性字典中 return value # 如果加了set,将该非数据描述符变为数据描述符,优先级高于实列属性,缓存能力丧失 # def __set__(self, instance, value): # print(‘hahahahahah‘) class Room: def __init__(self,name,width,length): self.name=name self.width=width self.length=length @Lazyproperty #area=Lazyproperty(area) 相当于‘定义了一个类属性,即描述符‘ def area(self): return self.width * self.length r1=Room(‘alex‘,1,1) print(r1.area) #先从自己的属性字典找,没有再去类的中找,然后出发了area的__get__方法 print(r1.area) #先从自己的属性字典找,找到了,是上次计算的结果,这样就不用每执行一次都去计算
property补充:一个静态属性property本质就是实现了get,set,delete三种方法
# -*- coding: utf-8 -*- class Foo: @property def AAA(self): print(‘get的时候运行我啊‘) @AAA.setter def AAA(self,value): print(‘set的时候运行我啊‘) @AAA.deleter def AAA(self): print(‘delete的时候运行我啊‘) #只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter f1=Foo() f1.AAA f1.AAA=‘aaa‘ del f1.AAA
应用(类型检测)
# -*- coding: utf-8 -*- class People: def __init__(self,name): self.name=name #实例化就触发property @property def name(self): # return self.name #无限递归 print(‘get------>‘) return self.DouNiWan @name.setter def name(self,value): print(‘set------>‘) if not isinstance(value,str): raise TypeError(‘必须是字符串类型‘) self.DouNiWan=value @name.deleter def name(self): print(‘delete------>‘) del self.DouNiWan p1=People(‘alex‘) #self.name实际是存放到self.DouNiWan里 print(p1.name) print(p1.__dict__) p1.name=1
元类
所有定义的类都是由type产生的。
# -*- coding: utf-8 -*- class foo: pass print(type(foo))
定义类的两种方法
# -*- coding: utf-8 -*- class foo: pass print(type(foo)) print(foo) def __init__(self,name,age): self.name=name self.age=age def test(self): print(‘=======>‘) Foo=type(‘foo1‘,(object,),{‘x‘:1,‘__init__‘:__init__,‘test‘:test}) print(Foo) print(Foo.__dict__) foo_1=Foo(‘alex‘,22) foo_1.test()
自定义元类(详情查看连接)