我有一个装饰器类validatekeys()
和一个Node3D()
类。
意图是Node3D
保存使用@property
装饰器检索的x,y和z的坐标值,并且可以使用@coords.setter
装饰器设置(致电set_coords()
)或直接使用set_coords()
,validatekeys()
本身饰有Node2D()
。我正在使用装饰器来实现这一点,以便我可以在以后添加其他类,例如class validatekeys(object):
def __init__(self,*keysIterable):
self.validkeys = []
for k in keysIterable:
self.validkeys.append(k)
def __call__(self,f):
def wrapped_f(*args,**kwargs):
for a in kwargs:
if not a in self.validkeys:
raise Exception()
self.__dict__.update(kwargs)
return f(self,**kwargs)
return wrapped_f
class Node3D(object):
@property
def coords(self):
return self.__dict__
@coords.setter
def coords(self,Coords):
self.set_coords(**Coords)
@validatekeys('x','y','z')
def set_coords(self,**Coords):
pass
。
代码:
n = Node2D()
n.coords #{} <--expected
n.set_coords(x=1,y=2)
n.coords #{} <--not expected
n.set_coords(a=1,b=2) #Exception <--expected
但是,部分输出不符合预期:
self.__dict__
看起来{{1}}未正确更新。但是,我一直无法弄清楚如何解决这个问题。有什么建议吗?
请注意,虽然我当然对解决此问题的替代公式/方法感兴趣(验证输入到setter的键输入),但这主要是学习装饰器,类等等如何工作的学习练习。
答案 0 :(得分:2)
你的装饰者正在更新错误的__dict__
;装饰器self
中的__call__
是装饰器对象本身。
您需要从被调用的包装器中提取绑定的self
参数:
def wrapped_f(*args, **kwargs):
for a in kwargs:
if not a in self.validkeys:
raise Exception()
instance = args[0]
instance.__dict__.update(kwargs)
return f(*args, **kwargs)
您也可以给wrapped_f()
明确的第一个参数:
def wrapped_f(instance, *args, **kwargs):
for a in kwargs:
if not a in self.validkeys:
raise Exception()
instance.__dict__.update(kwargs)
return f(instance, *args, **kwargs)
此处instance
绑定到Node3D
实例。请注意,没有必要命名此变量self
;这只是一个惯例。
答案 1 :(得分:1)
self
中的__call__
引用验证器,而不是Node3D对象,因此验证器正在更新自己的__dict__
。试试这个:
class validatekeys(object):
def __init__(self,*keysIterable):
self.validkeys = []
for k in keysIterable:
self.validkeys.append(k)
def __call__(validator_self,f):
def wrapped_f(self, *args,**kwargs):
for a in kwargs:
if not a in validator_self.validkeys:
raise Exception()
self.__dict__.update(kwargs)
return f(self, *args, **kwargs)
return wrapped_f
我已将self
中的__call__
重命名为validator_self
,以明确该自我引用验证者。我在包装函数中添加了self
;这个self
将引用经过验证的方法所在的Node3D对象的“真实”自我。