python2.x的新式类和python3.x的全部类,内置操作表达式调用,不会触发__getattr__()和__getattribute__()。参考《python的getattr和getattribute拦截内置操作》。
NO | 内置操作表达式(隐式调用) | 对应方法(显式调用) |
---|---|---|
1 | 索引操作[i] | __getitem__ |
2 | 加法(连接)操作+ | __coerce__ __add__ |
3 | 括号调用() | __call__ |
4 | 打印print() | __str__ |
__coerce__:表示强制类型转换,使用加法(或连接)操作+时,不同类型会触发类型转换或者报错。
内置操作调用方式:隐式调用,即调用表达式;显式调用,即调用方法名。
描述
内置操作的表达式调用,无法在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'
描述
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