Python——编写类装饰器
来源:互联网 发布:淘宝客app在线制作 编辑:程序博客网 时间:2024/06/06 04:46
编写类装饰器
程序输出如下:
类装饰器为编写这种__getattr__技术来包装一个完整接口提供了一个替代的、方便的方法。如下:
Spam和Person类的实例上的属性获取都会调用Wrapper类中的__getattr__逻辑,由于food和bob确实都是Wrapper的实例,得益于装饰器的实例创建调用重定向,输出如下:
类装饰器类似于函数装饰器的概念,但它应用于类,它们可以用于管理类自身,或者用来拦截实例创建调用以管理实例。
-------------------------------------------------------------------------------------------------------------------------------------
单体类
由于类装饰器可以拦截实例创建调用,所以它们可以用来管理一个类的所有实例,或者扩展这些实例的接口。
下面的类装饰器实现了传统的单体编码模式,即最多只有一个类的一个实例存在。
instances = {} # 全局变量,管理实例def getInstance(aClass, *args): if aClass not in instances: instances[aClass] = aClass(*args) return instances[aClass] #每一个类只能存在一个实例def singleton(aClass): def onCall(*args): return getInstance(aClass,*args) return onCall为了使用它,装饰用来强化单体模型的类:
@singleton # Person = singleton(Person)class Person: def __init__(self,name,hours,rate): self.name = name self.hours = hours self.rate = rate def pay(self): return self.hours * self.rate@singleton # Spam = singleton(Spam)class Spam: def __init__(self,val): self.attr = val bob = Person('Bob',40,10)print(bob.name,bob.pay())sue = Person('Sue',50,20)print(sue.name,sue.pay())X = Spam(42)Y = Spam(99)print(X.attr,Y.attr)现在,当Person或Spam类稍后用来创建一个实例的时候,装饰器提供的包装逻辑层把实例构建调用指向了onCall,它反过来调用getInstance,以针对每个类管理并分享一个单个实例,而不管进行了多少次构建调用。
程序输出如下:
Bob 400Bob 40042 42在这里,我们使用全局的字典instances来保存实例,还有一个更好的解决方案就是使用Python3中的nonlocal关键字,它可以为每个类提供一个封闭的作用域,如下:
def singleton(aClass):instance = Nonedef onCall(*args):nonlocal instanceif instance == None:instance = aClass(*args)return instancereturn onCall当然,我们也可以用类来编写这个装饰器——如下代码对每个类使用一个实例,而不是使用一个封闭作用域或全局表:
class singleton:def __init__(self,aClass):self.aClass = aClassself.instance = Nonedef __call__(self,*args):if self.instance == None:self.instance = self.aClass(*args)return self.instance-------------------------------------------------------------------------------------------------------------------------------------
跟踪对象接口
类装饰器的另一个常用场景是每个产生实例的接口。类装饰器基本上可以在实例上安装一个包装器逻辑层,来以某种方式管理其对接口的访问。
前面,我们知道可以用__getattr__运算符重载方法作为包装嵌入到实例的整个对象接口的方法,以便实现委托编码模式。__getattr__用于拦截未定义的属性名的访问。如下例子所示:
class Wrapper:def __init__(self,obj):self.wrapped = objdef __getattr__(self,attrname):print('Trace:',attrname)return getattr(self.wrapped,attrname)>>> x = Wrapper([1,2,3])>>> x.append(4)Trace: append>>> x.wrapped[1, 2, 3, 4]>>>>>> x = Wrapper({'a':1,'b':2})>>> list(x.keys())Trace: keys['b', 'a']在这段代码中,Wrapper类拦截了对任何包装对象的属性的访问,打印出一条跟踪信息,并且使用内置函数getattr来终止对包装对象的请求。
类装饰器为编写这种__getattr__技术来包装一个完整接口提供了一个替代的、方便的方法。如下:
def Tracer(aClass): class Wrapper: def __init__(self,*args,**kargs): self.fetches = 0 self.wrapped = aClass(*args,**kargs) def __getattr__(self,attrname): print('Trace:'+attrname) self.fetches += 1 return getattr(self.wrapped,attrname) return Wrapper@Tracerclass Spam: def display(self): print('Spam!'*8)@Tracerclass Person: def __init__(self,name,hours,rate): self.name = name self.hours = hours self.rate = rate def pay(self): return self.hours * self.ratefood = Spam()food.display()print([food.fetches])bob = Person('Bob',40,50)print(bob.name)print(bob.pay())print('')sue = Person('Sue',rate=100,hours = 60)print(sue.name)print(sue.pay())print(bob.name)print(bob.pay())print([bob.fetches,sue.fetches])通过拦截实例创建调用,这里的类装饰器允许我们跟踪整个对象接口,例如,对其任何属性的访问。
Spam和Person类的实例上的属性获取都会调用Wrapper类中的__getattr__逻辑,由于food和bob确实都是Wrapper的实例,得益于装饰器的实例创建调用重定向,输出如下:
Trace:displaySpam!Spam!Spam!Spam!Spam!Spam!Spam!Spam![1]Trace:nameBobTrace:pay2000Trace:nameSueTrace:pay6000Trace:nameBobTrace:pay2000[4, 2]========================================================================================
示例:实现私有属性
如下的类装饰器实现了一个用于类实例属性的Private声明,也就是说,属性存储在一个实例上,或者从其一个类继承而来。不接受从装饰的类的外部对这样的属性的获取和修改访问,但是,仍然允许类自身在其方法中自由地访问那些名称。类似于Java中的private属性。
traceMe = Falsedef trace(*args): if traceMe: print('['+ ' '.join(map(str,args))+ ']')def Private(*privates): def onDecorator(aClass): class onInstance: def __init__(self,*args,**kargs): self.wrapped = aClass(*args,**kargs) def __getattr__(self,attr): trace('get:',attr) if attr in privates: raise TypeError('private attribute fetch:'+attr) else: return getattr(self.wrapped,attr) def __setattr__(self,attr,value): trace('set:',attr,value) if attr == 'wrapped': # 这里捕捉对wrapped的赋值 self.__dict__[attr] = value elif attr in privates: raise TypeError('private attribute change:'+attr) else: # 这里捕捉对wrapped.attr的赋值 setattr(self.wrapped,attr,value) return onInstance return onDecoratorif __name__ == '__main__': traceMe = True @Private('data','size') class Doubler: def __init__(self,label,start): self.label = label self.data = start def size(self): return len(self.data) def double(self): for i in range(self.size()): self.data[i] = self.data[i] * 2 def display(self): print('%s => %s'%(self.label,self.data)) X = Doubler('X is',[1,2,3]) Y = Doubler('Y is',[-10,-20,-30]) print(X.label) X.display() X.double() X.display() print(Y.label) Y.display() Y.double() Y.label = 'Spam' Y.display() # 这些访问都会引发异常 """ print(X.size()) print(X.data) X.data = [1,1,1] X.size = lambda S:0 print(Y.data) print(Y.size())这个示例运用了装饰器参数等语法,稍微有些复杂,运行结果如下:
[set: wrapped <__main__.Doubler object at 0x03421F10>][set: wrapped <__main__.Doubler object at 0x031B7470>][get: label]X is[get: display]X is => [1, 2, 3][get: double][get: display]X is => [2, 4, 6][get: label]Y is[get: display]Y is => [-10, -20, -30][get: double][set: label Spam][get: display]Spam => [-20, -40, -60]
0 0
- Python——编写类装饰器
- Python——编写函数装饰器
- python—装饰器
- python—装饰器
- python装饰器装饰类
- Python——装饰器
- python——装饰器
- Python装饰器探究——装饰器参数
- Python 类装饰器
- python 类装饰器
- Python 装饰器装饰类中的方法
- Python 装饰器装饰类中的方法
- Python 装饰器装饰类中的方法
- python中的装饰器——@
- python中的装饰器——@
- Python编程学习——装饰器
- Python——装饰器基础
- python学习——装饰器
- [ssh新闻发布系统四]使用富文本编辑器发布新闻
- UpdatePanel学习
- (算法-training)前缀表达式
- Android 微信分享的几个坑
- c++MFC自定义消息的方法
- Python——编写类装饰器
- canpy测试
- GetBuffer()函数的使用
- C语言内存分配、指针强制转型和异地释放内存
- 23种设计模式
- python 索引和分片
- win7(64位)+vs2010+orge1.8.1
- 44.iOS 启动页面设置和 AppIcon设置
- 海量数据处理分析