Python装饰器重载内置的使用
作者:梯阅线条
本文主要介绍了Python装饰器重载内置的使用,详细介绍如何创建装饰器,如何使用装饰器来重载内置函数,具有一定的参考价值,感兴趣的可以了解一下
python2.x的新式类和python3.x的全部类,内置操作表达式调用,不会触发__getattr__()和__getattribute__()。参考《python的getattr和getattribute拦截内置操作》。
NO | 内置操作表达式(隐式调用) | 对应方法(显式调用) |
---|---|---|
1 | 索引操作[i] | __getitem__ |
2 | 加法(连接)操作+ | __coerce__ __add__ |
3 | 括号调用() | __call__ |
4 | 打印print() | __str__ |
__coerce__:表示强制类型转换,使用加法(或连接)操作+时,不同类型会触发类型转换或者报错。
内置操作调用方式:隐式调用,即调用表达式;显式调用,即调用方法名。
1.1 Py3内置操作表达式调用无法委托
描述
内置操作的表达式调用,无法在python3.0下委托,因为不会触发__getattr__()和__getattribute__()。
示例
>>> def traceCall(*args):#跟踪调用 if trace: print('['+','.join(map(str,args))+']') >>> def accessCtrl(forbid): def onDecorator(aCls): class onInstance: def __init__(self,*args,**kargs): self.__wrapped=aCls(*args,**kargs) def __getattr__(self,attr): traceCall('getattr',attr) if forbid(attr): raise TypeError('禁止访问:'+attr) else: return getattr(self.__wrapped,attr) def __setattr__(self,attr,value): traceCall('setattr',attr,value) # 压缩后的变量名为 _onInstance__wrapped if attr=='_onInstance__wrapped': self.__dict__[attr]=value elif forbid(attr): raise TypeError('禁止设置:'+attr) else: setattr(self.__wrapped,attr,value) return onInstance return onDecorator >>> def privateAttr(*privates): return accessCtrl(forbid=(lambda attr:attr in privates)) >>> @privateAttr('phone') class Staff_Private: def __init__(self,name,phone): self.name=name self.phone=phone def __str__(self): return 'Staff_Private->手机号:'+str(self.phone) def __add__(self,num): self.phone+=num
Python2.x执行
Py2的__getattr__()拦截print()和+等内置操作的表达式调用,正确的委托给装饰对象。
#python2.x执行 >>> trace=True >>> sp1=Staff_Private('梯阅线条',110) [setattr,_onInstance__wrapped,Staff_Private->手机号:110] #py2传统类 拦截内置操作表达式调用-隐式调用,print() >>> print(sp1) [getattr,__str__] Staff_Private->手机号:110 #py2传统类 拦截内置操作表达式调用-隐式调用,+ >>> sp1+1 [getattr,__coerce__] [getattr,__add__] >>> print(sp1) [getattr,__str__] Staff_Private->手机号:111
Python3.x执行
Py3的__getattr__()不拦截print()和+等内置操作的表达式调用,无法委托给装饰对象。
#python3.x执行 >>> trace=True >>> sp1=Staff_Private('梯阅线条',110) [setattr,_onInstance__wrapped,Staff_Private->手机号:110] #py3没有拦截内置操作 print >>> print(sp1) <__main__.accessCtrl.<locals>.onDecorator.<locals>.onInstance object at 0x0000019736C2F4F0> #py3没有拦截内置操作 + >>> sp1+1 Traceback (most recent call last): File "<pyshell#11>", line 1, in <module> sp1+1 TypeError: unsupported operand type(s) for +: 'onInstance' and 'int'
1.2 装饰器重载内置操作
描述
Python3.x的装饰器重载内置操作运算符方法,来拦截装饰类对应的内置表达式调用。
比如,重载__str__()拦截print(),__add__()拦截+。
示例
>>> def traceCall(*args):#跟踪调用 if trace: print('['+','.join(map(str,args))+']') >>> def accessCtrl(forbid): def onDecorator(aCls): class onInstance: def __init__(self,*args,**kargs): self.__wrapped=aCls(*args,**kargs) def __getattr__(self,attr): traceCall('getattr',attr) if forbid(attr): raise TypeError('禁止访问:'+attr) else: return getattr(self.__wrapped,attr) def __setattr__(self,attr,value): traceCall('setattr',attr,value) # 压缩后的变量名为 _onInstance__wrapped if attr=='_onInstance__wrapped': self.__dict__[attr]=value elif forbid(attr): raise TypeError('禁止设置:'+attr) else: setattr(self.__wrapped,attr,value) # print()触发__str__() def __str__(self): traceCall('onInstance,__str__') # str()触发__str__() return str(self.__wrapped) # + 触发 __add__() def __add__(self,other): traceCall('onInstance,__add__',other) return self.__wrapped+other return onInstance return onDecorator >>> def privateAttr(*privates): return accessCtrl(forbid=(lambda attr:attr in privates)) >>> @privateAttr('phone') class Staff_Private: def __init__(self,name,phone): self.name=name self.phone=phone def __str__(self): traceCall('Staff_Private,__str__') return 'Staff_Private->手机号:'+str(self.phone) def __add__(self,num): traceCall('Staff_Private,__add__',num) self.phone+=num >>> trace=True >>> sp1=Staff_Private('梯阅线条',110) [Staff_Private,__str__]#traceCall调用print()触发__str__() [setattr,_onInstance__wrapped,Staff_Private->手机号:110] # print()触发__str__() >>> print(sp1) [onInstance,__str__] [Staff_Private,__str__] Staff_Private->手机号:110 # + 触发 __add__() >>> sp1+1 [onInstance,__add__,1] [Staff_Private,__add__,1] >>> print(sp1) [onInstance,__str__] [Staff_Private,__str__] Staff_Private->手机号:111
到此这篇关于Python装饰器重载内置的使用的文章就介绍到这了,更多相关Python装饰器重载内置内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!