带参数的装饰器?

新手上路,请多包涵

我在装饰器转移变量 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

原文由 falek.marcin 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 321
2 个回答

带参数的装饰器的语法有点不同——带参数的装饰器应该返回一个函数,该函数将 接受一个函数 并返回另一个函数。所以它应该真的返回一个普通的装饰器。有点混乱,对吧?我的意思是:

 def decorator_factory(argument):
    def decorator(function):
        def wrapper(*args, **kwargs):
            funny_stuff()
            something_with_argument(argument)
            result = function(*args, **kwargs)
            more_funny_stuff()
            return result
        return wrapper
    return decorator

在这里 您可以阅读有关该主题的更多信息 - 也可以使用可调用对象来实现这一点,那里也对此进行了解释。

原文由 t.dubrownik 发布,翻译遵循 CC BY-SA 4.0 许可协议

编辑:要深入了解装饰器的心智模型,请查看 这个 很棒的 Pycon Talk。非常值得 30 分钟。

考虑带有参数的装饰器的一种方式是

@decorator
def foo(*args, **kwargs):
    pass

翻译成

foo = decorator(foo)

所以如果装饰器有参数,

 @decorator_with_args(arg)
def foo(*args, **kwargs):
    pass

翻译成

foo = decorator_with_args(arg)(foo)

decorator_with_args 是一个接受自定义参数并返回实际装饰器(将应用于装饰函数)的函数。

我使用了一个简单的部分技巧来简化我的装饰器

from functools import partial

def _pseudo_decor(fun, argument):
    def ret_fun(*args, **kwargs):
        #do stuff here, for eg.
        print ("decorator arg is %s" % str(argument))
        return fun(*args, **kwargs)
    return ret_fun

real_decorator = partial(_pseudo_decor, argument=arg)

@real_decorator
def foo(*args, **kwargs):
    pass

更新:

以上, foo 变成 real_decorator(foo)

装饰函数的一个效果是名称 foo 在装饰器声明时被覆盖。 fooreal_decorator 返回的任何内容“覆盖”。在这种情况下,一个新的函数对象。

foo 的所有元数据都被覆盖,特别是文档字符串和函数名称。

 >>> print(foo)
<function _pseudo_decor.<locals>.ret_fun at 0x10666a2f0>

functools.wraps 为我们提供了一种方便的方法来将文档字符串和名称“提升”到返回的函数中。

 from functools import partial, wraps

def _pseudo_decor(fun, argument):
    # magic sauce to lift the name and doc of the function
    @wraps(fun)
    def ret_fun(*args, **kwargs):
        # pre function execution stuff here, for eg.
        print("decorator argument is %s" % str(argument))
        returned_value =  fun(*args, **kwargs)
        # post execution stuff here, for eg.
        print("returned value is %s" % returned_value)
        return returned_value

    return ret_fun

real_decorator1 = partial(_pseudo_decor, argument="some_arg")
real_decorator2 = partial(_pseudo_decor, argument="some_other_arg")

@real_decorator1
def bar(*args, **kwargs):
    pass

>>> print(bar)
<function __main__.bar(*args, **kwargs)>

>>> bar(1,2,3, k="v", x="z")
decorator argument is some_arg
returned value is None

原文由 srj 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题