我有装饰器传递变量'insurance_mode'的问题 . 我会通过以下装饰器声明来做到这一点:
@execute_complete_reservation(True)
def test_booking_gta_object(self):
self.test_select_gta_object()
但不幸的是,这种说法不起作用 . 或许也许有更好的方法来解决这个问题 .
def execute_complete_reservation(test_case,insurance_mode):
def inner_function(self,*args,**kwargs):
self.test_create_qsf_query()
test_case(self,*args,**kwargs)
self.test_select_room_option()
if insurance_mode:
self.test_accept_insurance_crosseling()
else:
self.test_decline_insurance_crosseling()
self.test_configure_pax_details()
self.test_configure_payer_details
return inner_function
7 回答
你的意思是
def test_booking_gta_object
,对吗?无论如何,带参数的装饰器的语法有点不同 - 带参数的装饰器应返回一个函数,该函数将接受一个函数并返回另一个函数 . 所以它应该真正返回一个普通的装饰器 . 有点混乱,对吧?我的意思是:Here您可以阅读有关该主题的更多信息 - 也可以使用可调用对象实现此功能,并在此处进行了解释 .
考虑带参数的装饰器的一种方法是
翻译成
所以如果装饰者有参数,
翻译成
decorator_with_args
是一个接受自定义参数并返回实际装饰器(将应用于修饰函数)的函数 .我使用一个简单的技巧与partials使我的装饰器容易
更新:
以上,
foo
成为real_decorator(foo)
装饰函数的一个作用是在装饰器声明时重写名称
foo
.foo
是"overridden"由real_decorator
返回的任何内容 . 在这种情况下,一个新的函数对象 .所有
foo
的元数据都被覆盖,特别是docstring和函数名称 .functools.wraps为我们提供了一个方便的方法_文件名和返回函数的名称"lift" .
我想展示一个恕我直言,非常优雅的想法 . t.dubrownik提出的解决方案显示了一个始终相同的模式:无论装饰器做什么,都需要三层包装器 .
所以我认为这是一个元装饰器的工作,也就是装饰器的装饰器 . 由于装饰器是一个函数,它实际上作为带有参数的常规装饰器:
这可以应用于常规装饰器以添加参数 . 例如,假设我们有装饰器,它将函数的结果加倍:
使用
@parametrized
,我们可以构建一个具有参数的通用@multiply
装饰器通常,参数化装饰器的第一个参数是函数,而其余参数将对应于参数化装饰器的参数 .
一个有趣的用法示例可能是类型安全的断言装饰器:
最后一点:这里我没有使用
functools.wraps
作为包装函数,但我建议一直使用它 .这是t.dubrownik's answer的略微修改版本 . 为什么?
作为通用模板,您应该从原始函数返回返回值 .
这会更改函数的名称,这可能会影响其他装饰器/代码 .
所以使用@functools.wraps():
我认为你的问题是将参数传递给你的装饰者 . 这有点棘手,并不简单 .
以下是如何执行此操作的示例:
打印:
See Bruce Eckel's article for more details.
在我的实例中,我决定通过一行lambda来解决这个问题,以创建一个新的装饰器函数:
执行时,会打印:
也许不像其他解决方案那样可扩展,但对我有用 .
定义这个“decoratorize函数”来生成自定义的装饰器函数:
以这种方式使用它: