通过带参的函数装饰器返回一个包装类/委托类(主要实现了__getattr__ , __setattr__来拦截属性),
使用装饰器及委托类的好处是不用每个类都去实现__setattr__, __getattribute__ ,对你没看错是__getattribute__.
在委托类中只需实现__getattr__ 即可.
简单区别:
__getattribute__ : 实例对象通过 .(点) 操作符都会触发
__getattr__ :获取未定义的属性会触发
委托类的模式有点像shell , 被装饰的类有点像内核. 内核中随意弄, 而操作shell却有限制.
装饰器的好处就在于完全和主体分离.
#通过装饰器实现私有属性
#整体基于一个委托类
#主要通过__getattr__ , __setattr__ 来拦截属性的访问以及设置
def print_trace(*args): #输出语句
print('['+' '.join(map(str,args)) +']')
#带参数的函数装饰器,返回一个包装类
def Private(*privates): #privates 接受一系列的私有属性
def decorator(aClass): #函数装饰器,接受一个类对象
class private_class: #返回的包装类
errstr_getattr = '获取私有属性失败'
errstr_setattr = '设置私有属性失败'
def __init__(self,*args,**kwargs):
self.wrapper = aClass(*args,**kwargs) #实例属性wrapper 创建一个被装饰类的对象
def __getattr__(self, attr): #用于wrapper对象的属性获取
print_trace('__getattr__:',attr)
if attr in privates: #通过闭包引用的额外作用域,获取privates元组,如果attr是私有属性则抛异常
raise TypeError(private_class.errstr_getattr+':'+str(attr))
return getattr(self.wrapper,attr) #不是一开始设置的私有属性,则通过getattr获取
def __setattr__(self, attr, value): #用于wrapper对象的属性设置
print_trace('__setattr__:',attr,value)
if 'wrapper' == attr: #'wrapper'属性是委托类自己的属性,放行
object.__setattr__(self,attr,value) #或者使用self.__dict__[attr] = value , 两者皆可
elif attr in privates: #如果attr是私有属性则出错
raise TypeError(private_class.errstr_setattr+':'+str(attr))
else:
object.__setattr__(self.wrapper,attr,value) #委托类自身只有一个wrapper属性,其他属性通过wrapper对象获取
return private_class
return decorator
@Private("data",'size') #把data,size作为私有属性
class TestClass:
def __init__(self,label,start):
self.label = label
self.data = start
def size(self):
return len(self.data)
def double(self):
for i in range(self.size()):
self.data[i] = self.data[i] * 2
def display(self):
print("%s => %s"%(self.label,self.data))
t = TestClass()
#t.data , t.size 将出错
#通用的Private, Public 装饰器
#打印函数
def trace(*args):
print('[' +' '.join(map(str,args))+']')
#通用的函数装饰器
#4层结构
#同样的通过委托类来实现
def access_func(test_func): #接受一个函数对象,用于判断是否是私有,公有属性
def decorator(aClass): #装饰器
class WrappedClass: #返回的内部类
err_getattr = "获取私有属性失败"
err_setattr = "设置私有属性失败"
def __init__(self,*args, **kwargs):
self.wrapped = aClass(*args,**kwargs) #被装饰的对象
def __getattr__(self, attr): #__getattr__ 拦截未知属性
if test_func(attr): #私有公有属性主要通过 闭包中的test_func 来判断
raise TypeError(WrappedClass.err_getattr,attr)
return getattr(self.wrapped,attr)
def __setattr__(self, attr, value):
if 'wrapped' == attr: #WrappedClass自身属性通过
object.__setattr__(self,attr,value)
elif test_func(attr):
raise TypeError(WrappedClass.err_setattr,attr)
else:
object.__setattr__(self.wrapped,attr,value)
return WrappedClass
return decorator
#最上层的函数包裹,通过调用access_func 来返回装饰器
#通过传入匿名函数给下面函数使用,最内层的WrappedClass通过闭包来获取
def private_decorator(*private_attrs): #传入私有属性,当外部访问私有属性抛异常
return access_func(lambda attr: attr in private_attrs)
def public_decorator(*public_attrs): #传入共有属性,当外部访问非公有属性时抛异常
return access_func(lambda attr : attr not in public_attrs)
@public_decorator('age') #测试
class Person:
def __init__(self,name='Person',age=10):
self.name = name
self.age = age
p = Person()
print(p.age) #ok
print(p.name) #error
最后提供一种很烂的方法来实现私有属性,公有属性
#私有,公有属性用 __getattribute__ 来实现
#只提供一种思路
def access_control(test_func):
def decorator(aClass):
def getattr(self,attr):
print('get:',attr)
if test_func(attr):
raise TypeError('私有属性获取失败 :' ,attr)
return object.__getattribute__(self,attr)
aClass.__getattribute__ = getattr #核心代码就这一句
return aClass
return decorator
def private_decorator(*args):
return access_control(lambda attr : attr in args)
def public_decorator(*args):
return access_control(lambda attr : attr not in args)