Python装饰器实现私有属性

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]=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

你可能感兴趣的:(python,python)