我觉得我在处理常规函数时很好地掌握了使用装饰器,但是在派生类中使用基类方法进行装饰,并将参数传递给所述装饰器之后,我无法弄清楚下一步该做什么。 这是一段代码。
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
尝试,我找不到“自我”
我也一直在努力使apply_validation
类方法没有成功。
有人请解释我做错了什么,以及解决这个问题的最佳方法吗?谢谢。
答案 0 :(得分:1)
只是在类方法上使用装饰器的一个例子:
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
答案 1 :(得分:1)
您遇到的问题是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
中包含继承的方法,您可能需要修改ValidatedMeta.__new__
中的逻辑。可能最简单的方法是在_validations
中查找bases
属性并将列表连接在一起。