使用装饰器作为类属性而不是实例属性

时间:2014-10-30 12:48:51

标签: python

我有以下课程。

Validator是一个装饰器,它接收一个定义装饰函数验证标准的类。 ValidateKeys是此示例的验证条件。 Node2D是使用验证标准的类。

class Validator(object):
    def __init__(self, TheValidator, *args, **kwargs):
        self.validator = TheValidator(*args,**kwargs)
    def __call__(self,f):
        def wrapped_f(instance, *args,**kwargs):
            self.TheValidator(instance, *args, **kwargs)
            return f(instance,*args,**kwargs)
        return wrapped_f

class ValidateKeys(object):
    def __init__(self,*keysIterable):
        self.validkeys = keysIterable
    def __call__(self, instance, **kwargs):
        for a in kwargs:
            if not a in self.validkeys:
                raise Exception()
        instance.__dict__.update(kwargs)

class Node2D(object):
    @property
    def coords(self):
        return self.__dict__
    @coords.setter
    def coords(self,Coords):
        self.set_coords(**Coords)
    @Validator(ValidateKeys, 'x','y')
    def set_coords(self,**Coords):
        pass

根据我的理解,正如本文所述,Node2D的每个实例都会产生重复的Validator(与Validator装饰的任何其他类一样)和{{1} }。

编辑:THIS IS WRONG请参阅下面的答案。

请注意,这主要是我的学习练习,虽然我有兴趣听取批评/建议以改进我的所有方法,但我的主要目标是了解如何有效地使用装饰器。

另请注意,我通常不会对装饰器类使用大写,但我在此处使用它,因为它使得在SO上更容易阅读。

1 个答案:

答案 0 :(得分:2)

我的假设不正确。

编写内容时,每个类只创建一个ValidatorValidateKeys实例。我没有意识到行@Validator(ValidateKeys, 'x','y')只运行一次(在类定义时)而不是在实例创建时运行。

应该意识到这一点,因为装饰器表达式出现在与class attributes相同的层次结构中,例如:

class MyClass():
    class_attribute = None #only one class_attribute is created
    @decorator             #only one decorator (i.e., decorated method) is created
    def method():
        pass

测试:

class Validator(object):
    def __init__(self, TheValidator, *args, **kwargs):
        print("New Validator Object")
        self.TheValidator = TheValidator(*args,**kwargs)
    def __call__(self,f):
        def wrapped_f(instance, *args,**kwargs):
            self.TheValidator(instance, *args, **kwargs)
            return f(instance,*args,**kwargs)
        return wrapped_f

class ValidateKeys(object):
    def __init__(self,*keysIterable):
        print("New ValidateKeys Object")
        self.validkeys = keysIterable
    def __call__(self, instance, **kwargs):
        for a in kwargs:
            if not a in self.validkeys:
                raise Exception()
        instance.__dict__.update(kwargs)

class Node2D(object):
    @property
    def coords(self):
        return self.__dict__
    @coords.setter
    def coords(self,Coords):
        self.set_coords(**Coords)
    @Validator(ValidateKeys, 'x','y')
    def set_coords(self,**Coords):
        pass

n1 = Node2D()
n2 = Node2D()
n1.setcoords(x=1,y=2)
n1.coords

输出:

'New Validator Object'    #<-- Seen only once when module is loaded (class defined)
'New ValidateKeys Object' #<-- Seen only once when module is loaded (class defined)
'{'x': 1, 'y': 2}'

我没有遇到过我认为的问题。感谢大家的帮助。