使用d验证属性名

2024-06-26 14:24:24 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个装饰类validatekeys()和一个Node3D()类。你知道吗

其意图是Node3D保存使用@property装饰器检索的x、y和z的坐标值,并且可以使用@coords.setter装饰器(调用set_coords())或直接使用本身用validatekeys()装饰的set_coords()来设置。我正在使用decorators来完成这个任务,以便以后可以添加其他类,例如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__没有正确更新。然而,我一直不知道如何解决这个问题。有什么建议吗?你知道吗

请注意,尽管我对解决这个问题的其他公式/方法(验证对setter的键输入)很感兴趣,但这主要是一个学习练习,以了解decorator、类等是如何工作的。你知道吗


Tags: inselfreturndef装饰coordsdictkwargs
2条回答

您的__call__中的self引用的是验证器,而不是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

在这里,我将__call__中的self重命名为validator_self,以明确该self引用了验证器。我在包装函数中添加了一个self;这个self将引用Node3D对象的“真实”自我,其中验证的方法是。你知道吗

您的decorator正在更新错误的__dict__self在您的decorator中__call__decorator对象本身。你知道吗

您需要从被调用的包装器中提取绑定的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并没有硬性要求;这只是一个约定。你知道吗

相关问题 更多 >