1 Python装饰器实现私有属性
从装饰类的外部获取和修改指定属性,进行报错处理,允许类自身在其方法中访问和修改指定属性。
装饰类将私有属性传给装饰器入参,装饰器重载属性点号运算和赋值运算,来拦截属性访问和设置,若为私有属性则禁止访问和设置,通过委托的方式区分装饰类和装饰器的属性。
1.1 描述
使用装饰类入参存储私有属性列表,通过委托和__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设置,避免循环;
1.2 示例
>>> 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]=valueelif attr in privates:# 装饰类私有属性处理raise TypeError('禁止设置:'+attr)else:# 非私有属性通过装饰类实例设置属性setattr(self.wrapped,attr,value)return OnInstancereturn onDecorator>>> trace=True
>>> @privateAttr('data','size')
class Triple:def __init__(self,tag,beg):self.tag=tagself.data=begdef size(self):return len(self.data)def mul3(self):for i in range(self.size()):self.data[i]=self.data[i]*3def 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 "<pyshell#66>", line 1, in <module>print(t1.size())File "<pyshell#51>", line 9, in __getattr__raise TypeError('禁止访问:'+attr)
TypeError: 禁止访问:size
>>> print(t1.data)
[getattr,data]
Traceback (most recent call last):File "<pyshell#67>", line 1, in <module>print(t1.data)File "<pyshell#51>", 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 "<pyshell#68>", line 1, in <module>t1.data=[1,2,3]File "<pyshell#51>", 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 "<pyshell#69>", line 1, in <module>t1.size=lambda n:10File "<pyshell#51>", line 17, in __setattr__raise TypeError('禁止设置:'+attr)
TypeError: 禁止设置:size
>>> print(t2.data)
[getattr,data]
Traceback (most recent call last):File "<pyshell#70>", line 1, in <module>print(t2.data)File "<pyshell#51>", line 9, in __getattr__raise TypeError('禁止访问:'+attr)
TypeError: 禁止访问:data
>>> print(t2.size())
[getattr,size]
Traceback (most recent call last):File "<pyshell#71>", line 1, in <module>print(t2.size())File "<pyshell#51>", line 9, in __getattr__raise TypeError('禁止访问:'+attr)
TypeError: 禁止访问:size