从装饰类的外部获取和修改指定属性,进行报错处理,允许类自身在其方法中访问和修改指定属性。
装饰类将私有属性传给装饰器入参,装饰器重载属性点号运算和赋值运算,来拦截属性访问和设置,若为私有属性则禁止访问和设置,通过委托的方式区分装饰类和装饰器的属性。
使用装饰类入参存储私有属性列表,通过委托和__getattr__()、__setattr__()实现装饰类的属性访问和设置。
(1) 类装饰器最外层定义privateAttr函数,接收私有属性列表privates;
(2) 次外层定义onDecorator函数,接收装饰类;
(3) 次外层onDecorator函数主体,定义委托类onInstance,拦截装饰类的属性访问和设置;
(4) 将装饰类实例赋值给装饰器实例属性self.wrapped实现委托;
(5) 通过__getattr__()拦截未定义属性的点号运算,即装饰类属性;
(6) 通过__setattr__()拦截全部属性的赋值运算;
(7) 在私有属性列表内的属性,禁止访问和设置,进行抛错处理;
(8) 非私有属性访问通过getattr()转到装饰类实例上返回;
(9) 非私有属性设置通过setattr()转到装饰类实例上设置;
(10) 装饰器实例属性设置,通过self.__dict__[attr]=val设置,避免循环;
>>> trace=False
>>> def traceCall(*args):#跟踪调用
if trace:
print('['+','.join(map(str,args))+']')
>>> def privateAttr(*privates):#装饰器参数-私有属性列表
def onDecorator(aCls):
class OnInstance:
def __init__(self,*args,**kargs):
# 装饰类实例委托给装饰器
self.wrapped=aCls(*args,**kargs)
def __getattr__(self,attr):
# 拦截非装饰器实例属性的访问
# 即拦截装饰类的属性访问
traceCall('getattr',attr)
# 在私有属性列表则禁止访问
if attr in privates:
raise TypeError('禁止访问:'+attr)
else:# 否则通过装饰类实例访问
return getattr(self.wrapped,attr)
def __setattr__(self,attr,value):
# 拦截全部属性设置
traceCall('setattr',attr,value)
if attr=='wrapped':# 装饰器属性设置处理
# __dict__ 避免循环设置属性
self.__dict__[attr]=value
elif attr in privates:# 装饰类私有属性处理
raise TypeError('禁止设置:'+attr)
else:# 非私有属性通过装饰类实例设置属性
setattr(self.wrapped,attr,value)
return OnInstance
return onDecorator
>>> trace=True
>>> @privateAttr('data','size')
class Triple:
def __init__(self,tag,beg):
self.tag=tag
self.data=beg
def size(self):
return len(self.data)
def mul3(self):
for i in range(self.size()):
self.data[i]=self.data[i]*3
def show(self):
print(self.tag,' -> ',self.data)
# t1=Triple('t1 是',[9,5,55]) 执行过程
# 触发调用onDecorator()->调用 OnInstance(),
# 即触发 OnInstance 的构造函数 __init__()
# 触发self.wrapped赋值运算
# wrapped点号运算不触发 __getattr__(),因为是自身属性
# wrapped赋值运算触发 __setattr__()
>>> t1=Triple('t1 是',[9,5,55])
[setattr,wrapped,<__main__.Triple object at 0x00000197322DE220>]
>>> t2=Triple('t2 是',[6,8,9])
[setattr,wrapped,<__main__.Triple object at 0x00000197322AF220>]
# t1.tag,t1.show,t1.mul3 装饰类属性触发 __getattr__()
# 非私有属性,通过装饰类实例访问
>>> print(t1.tag)
[getattr,tag]
t1 是
>>> t1.show()
[getattr,show]
t1 是 -> [9, 5, 55]
>>> t1.mul3()
[getattr,mul3]
>>> t1.show()
[getattr,show]
t1 是 -> [27, 15, 165]
>>> print(t2.tag)
[getattr,tag]
t2 是
>>> t2.show()
[getattr,show]
t2 是 -> [6, 8, 9]
>>> t2.mul3()
[getattr,mul3]
>>> t2.show()
[getattr,show]
t2 是 -> [18, 24, 27]
>>> t2.tag='梯阅线条'
[setattr,tag,梯阅线条]
>>> t2.show()
[getattr,show]
梯阅线条 -> [18, 24, 27]
# size 和 data 私有属性,禁止访问和设置
>>> print(t1.size())
[getattr,size]
Traceback (most recent call last):
File "" , line 1, in <module>
print(t1.size())
File "" , line 9, in __getattr__
raise TypeError('禁止访问:'+attr)
TypeError: 禁止访问:size
>>> print(t1.data)
[getattr,data]
Traceback (most recent call last):
File "" , line 1, in <module>
print(t1.data)
File "" , line 9, in __getattr__
raise TypeError('禁止访问:'+attr)
TypeError: 禁止访问:data
>>> t1.data=[1,2,3]
[setattr,data,[1, 2, 3]]
Traceback (most recent call last):
File "" , line 1, in <module>
t1.data=[1,2,3]
File "" , line 17, in __setattr__
raise TypeError('禁止设置:'+attr)
TypeError: 禁止设置:data
>>> t1.size=lambda n:10
[setattr,size,<function <lambda> at 0x00000197322D1940>]
Traceback (most recent call last):
File "" , line 1, in <module>
t1.size=lambda n:10
File "" , line 17, in __setattr__
raise TypeError('禁止设置:'+attr)
TypeError: 禁止设置:size
>>> print(t2.data)
[getattr,data]
Traceback (most recent call last):
File "" , line 1, in <module>
print(t2.data)
File "" , line 9, in __getattr__
raise TypeError('禁止访问:'+attr)
TypeError: 禁止访问:data
>>> print(t2.size())
[getattr,size]
Traceback (most recent call last):
File "" , line 1, in <module>
print(t2.size())
File "" , line 9, in __getattr__
raise TypeError('禁止访问:'+attr)
TypeError: 禁止访问:size