Python 使用将参数作为派生类函数装饰器的基类函数

Python 使用将参数作为派生类函数装饰器的基类函数,python,decorator,Python,Decorator,我觉得在处理常规函数时,我对使用decorator有很好的掌握,但是在派生类中为decorator使用基类方法,以及将参数传递给所述decorator之间,我不知道下一步该怎么做。 下面是一段代码 class ValidatedObject: ... def apply_validation(self, field_name, code): def wrap(self, f): self._validations.append(Valid

我觉得在处理常规函数时,我对使用decorator有很好的掌握,但是在派生类中为decorator使用基类方法,以及将参数传递给所述decorator之间,我不知道下一步该怎么做。 下面是一段代码

class ValidatedObject: ... def apply_validation(self, field_name, code): def wrap(self, f): self._validations.append(Validation(field_name, code, f)) return f return wrap class test(ValidatedObject): .... @apply_validation("_name", "oh no!") def name_validation(self, name): return name == "jacob" 类验证对象: ... def应用验证(自身、字段名称、代码): def包裹(自,f): self.\u validations.append(验证(字段名称、代码、f)) 返回f 回程包装 类测试(ValidatedObject): .... @应用验证(“\u名称”,“哦,不!”) def名称\u验证(自身,名称): 返回名称==“jacob” 如果我按原样尝试此操作,则未找到“应用验证”。
如果我用
@self.apply\u validation
尝试,我会发现一个“self”没有找到。
我还一直在胡闹,把
apply\u验证
作为一个类方法,但没有成功


有人能解释一下我做错了什么,以及解决这个问题的最佳方法吗?谢谢。

这只是在类方法上使用装饰器的一个示例:

from functools import wraps

def VALIDATE(dec):
    @wraps(dec)
    def _apply_validation(self, name):
        self.validate(name)
        return dec(self, name)
    return _apply_validation

class A:
    def validate(self, name):
        if name != "aamir":
            raise Exception, 'Invalid name "%s"' % name

class B(A):

    @VALIDATE
    def name_validation(self, name):
        return name

b = B()
b.name_validation('jacob') # should raise exception

您遇到的问题是,
apply\u validation
是一种方法,这意味着您需要在
ValidatedObject
的实例上调用它。不幸的是,在调用它的时候(在定义
test
类的过程中),没有合适的实例可用。你需要一种不同的方法

最明显的一种方法是使用一个元类来搜索其实例字典(实际上是类字典),并根据找到的内容设置
\u validations
变量。您仍然可以使用decorator,但它可能应该是一个全局函数,或者是一个静态方法,并且需要以不同的方式工作。下面是一些使用元类和添加函数属性的装饰器的代码:

class ValidatedMeta(type):
    def __new__(meta, name, bases, dct):
        validations = [Validation(f._validation_field_name, f._validation_code, f)
                       for f in dct.values if hasattr(f._validation_field_name)]
        dct["_validations"] = validations
        super(ValidatedMeta, meta).__new__(meta, name, bases, dct)

def apply_validation(field_name, code):
    def decorator(f):
        f._validation_field_name = field_name
        f._validation_code = code
        return f
    return decorator

def ValidatedObject(metaclass=ValidatedMeta):
    pass

class test(ValidatedObject):
    @apply_validation("_name", "oh no!")
    def name_validation(self, name):
        return name == "jacob"
此代码运行后,
test.\u验证将是
[验证(“\u name”,“oh no!”,test.name\u验证)]
。请注意,传递给
Validation
的方法是未绑定的,因此您需要在调用它时自己传递一个
self
参数(或者可以删除
self
参数,并更改在
apply\u Validation
中创建的修饰符以返回
staticmethod(f)


如果在继承层次结构的多个级别上定义了验证方法,则此代码可能无法实现所需的功能。上面写的元类只检查立即类的dict中是否有具有适当属性的方法。如果需要在
\u validations
中包含继承的方法,则可能需要修改
ValidatedMeta.\uuuu new\uuuu
中的逻辑。可能最简单的方法是在
库中查找
\u validations
属性,并将列表连接在一起。

每个实例是否需要每个方法都有自己的
Validation
对象?@user2357112我认为每个测试对象只有一个验证对象。Validation对象包含一个所有验证测试的列表,当您调用一个方法来运行所有验证时,它只会遍历该列表。@jacobcase94检查我的答案。这有用吗?我不知道ValidatedObject是什么,所以我尽量简单。或者如果我误解了你的问题?子类是否应该相互继承验证?也就是说,如果一个类
test2
继承了示例代码中的
test
,那么它应该
test2.\u验证
包括为
“\u name”
创建的
验证
实例,还是应该把它留给其他继承的方法?@Blckknght更好。Python只是变得更复杂了。这是非常有用的,但是,我有一些处理要做。为什么新的需要4个参数。我很难理解它。我一直在读这个问题:谢谢。@jacobcase94:元类接受这些参数以匹配其超类的调用语法,(自动提供
meta
参数,就像常规的
\uuuuu新方法中的
cls
一样)。当定义了
ValidatedObject
test
类时,调用
ValidatedMeta
来构造类对象。你可以手工做。类语句等价于:
ValidatedObject=ValidatedMeta(“ValidatedObject”,(),{})