繁体   English   中英

使用将参数作为派生类函数的修饰符的基类函数

[英]Using a base class function that takes parameters as a decorator for derived class function

我觉得我在处理常规函数时非常了解使用装饰器,但是在派生类中使用装饰器的基类方法和将参数传递给所述装饰器之间,我不知道下一步该怎么做。 这是一段代码。

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"

如果按原样尝试,则会发现找不到“ apply_validation”。
如果我使用@self.apply_validation尝试,则@self.apply_validation “自我”。
我也一直在使apply_validation成为一个没有成功的类方法。

有人可以解释我在做什么错,以及解决此问题的最佳方法吗? 谢谢。

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

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_validation是一个方法,这意味着您需要在ValidatedObject的实例上调用它。 不幸的是,在调用它的时候(在test类的定义期间),没有合适的实例可用。 您需要一种不同的方法。

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

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._validations将为[Validation("_name", "oh no!", test.name_validation)] 请注意,传递给Validation是未绑定的,因此您在调用它时需要自己传递一个self参数(或者删除self参数并更改apply_validation创建的装饰器以返回staticmethod(f) )。 。

如果您在继承层次结构的多个级别上定义了验证方法,则此代码可能无法执行您想要的操作。 上面编写的元类仅检查直接类的dict是否具有适当属性的方法。 如果您还需要在_validations包括继承的方法, _validations可能需要修改ValidatedMeta.__new__的逻辑。 可能是要走的最简单的方法是看_validations在属性bases并连接列表在一起。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM