我正在尝试实现一个接受一些参数的装饰器。通常,带参数的装饰器实现为双嵌套闭包,如下所示:
def mydecorator(param1, param2):
# do something with params
def wrapper(fn):
def actual_decorator(actual_func_arg1, actual_func_arg2):
print("I'm decorated!")
return fn(actual_func_arg1, actual_func_arg2)
return actual_decorator
return wrapper
但就我个人而言,我不喜欢这种方法,因为它是非常不可读和难以理解。你知道吗
所以我就这样结束了:
class jsonschema_validate(object):
def __init__(self, schema):
self._schema = schema
def __call__(self, fn):
self._fn = fn
return self._decorator
def _decorator(self, req, resp, *args, **kwargs):
try:
jsonschema.validate(req.media, self._schema, format_checker=jsonschema.FormatChecker())
except jsonschema.ValidationError as e:
_log.exception('Validation failed: %r', e)
raise errors.HTTPBadRequest('Bad request')
return self._fn(req, resp, *args, **kwargs)
其思想非常简单:在实例化时,我们只捕获decorator参数,在调用时,我们捕获decorated函数并返回decorator实例的方法,该方法是绑定的。绑定它是很重要的,因为在decorator调用时,我们希望访问self
,并将所有信息存储在其中。你知道吗
然后我们用它来上课:
class MyResource(object):
@jsonschema_validate(my_resource_schema)
def on_post(self, req, resp):
pass
不幸的是,这种方法不起作用。问题是,在decorator调用时,我们会释放装饰实例的上下文,因为在装饰时(定义类时),装饰方法没有绑定。绑定稍后在属性访问时发生。但是现在我们已经有了decorator的绑定方法(jsonschema_validate._decorator
),并且self
是隐式传递的,它的值不是MyResource
实例,而是jsonschema_validate
实例。我们不想丢失这个值,因为我们想在decorator调用时访问它的属性。最后,当调用self._fn(req, resp, *args, **kwargs)
时,它会导致TypeError
,并抱怨“缺少所需的位置参数resp”,因为传入的req
arg变为MyResource.on_post
“self
”,所有参数实际上都“移位”。你知道吗
那么,有没有办法将decorator实现为一个类而不是一堆嵌套函数呢?你知道吗
当我第一次尝试将decorator实现为简单类时很快就失败了,我立即返回到嵌套函数。似乎正确实现的类方法更难理解和纠结,但我还是想找到解决方案,从中获得乐趣。你知道吗
这很有趣!谢谢你发布这个问题。你知道吗
编写一个不接受参数的简单装饰器相当容易,但是将其扩展到一个调用了三次的类则更具挑战性。我选择使用
functools.partial
来解决这个问题。你知道吗如您所见,我选择了带有钩子的设计来修改方法中的参数和响应。希望在大多数情况下,这样可以避免接触
__call__
或__new__
。你知道吗在返回
partial
之后,我想不出将params
附加到ParamsDecorator
的方法,所以我不得不选择将它放入SimpleDecorator
中,但不使用它。你知道吗我认为这在保持内容扁平化而不是嵌套化方面做得很好。我也喜欢这个可以为您处理
functools.wraps
,所以您不必担心在这些decorator中包含这个。以这种方式编写decorator的缺点是,您现在引入了一个新模块,您需要安装或维护该模块,然后在每次编写decorator时导入该模块。你知道吗相关问题 更多 >
编程相关推荐