我有一个由装饰器转移变量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

当前回答

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

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

在这里你可以读到更多关于这个主题的内容——也可以使用可调用对象来实现这个功能,这里也有解释。

其他回答

带参数的装饰器应该返回一个函数,该函数将接受一个函数,并返回另一个函数

def decorator_factory(argument):
    def decorator(function):
        def wrapper(*args, **kwargs):
            """
                add somhting
            """
            return  function(*args, **kwargs)
        return wrapper
    return decorator

或者你可以使用functools模块的部分

def decorator(function =None,*,argument ):
        if function is None :
            return partial(decorator,argument=argument)
        def wrapper(*args, **kwargs):
            """
                add somhting
            """
            return  function(*args, **kwargs)
        return wrapper

在第二个选项中,确保你像这样传递参数:

@decorator(argument = 'args')
def func():
    pass

这是一个函数装饰器模板,如果没有参数,则不需要(),并且支持位置参数和关键字参数(但需要检查locals(),以确定第一个参数是否是要装饰的函数):

import functools


def decorator(x_or_func=None, *decorator_args, **decorator_kws):
    def _decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kws):
            if 'x_or_func' not in locals() \
                    or callable(x_or_func) \
                    or x_or_func is None:
                x = ...  # <-- default `x` value
            else:
                x = x_or_func
            return func(*args, **kws)

        return wrapper

    return _decorator(x_or_func) if callable(x_or_func) else _decorator

下面是一个例子:

def multiplying(factor_or_func=None):
    def _decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            if 'factor_or_func' not in locals() \
                    or callable(factor_or_func) \
                    or factor_or_func is None:
                factor = 1
            else:
                factor = factor_or_func
            return factor * func(*args, **kwargs)
        return wrapper
    return _decorator(factor_or_func) if callable(factor_or_func) else _decorator


@multiplying
def summing(x): return sum(x)

print(summing(range(10)))
# 45


@multiplying()
def summing(x): return sum(x)

print(summing(range(10)))
# 45


@multiplying(10)
def summing(x): return sum(x)

print(summing(range(10)))
# 450

或者,如果不需要位置参数,可以不检查wrapper()中的第一个参数(从而不需要使用locals()):

import functools


def decorator(func_=None, **decorator_kws):
    def _decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kws):
            return func(*args, **kws)
        return wrapper

    if callable(func_):
        return _decorator(func_)
    elif func_ is None:
        return _decorator
    else:
        raise RuntimeWarning("Positional arguments are not supported.")

下面是一个例子:

import functools


def multiplying(func_=None, factor=1):
    def _decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            return factor * func(*args, **kwargs)
        return wrapper

    if callable(func_):
        return _decorator(func_)
    elif func_ is None:
        return _decorator
    else:
        raise RuntimeWarning("Positional arguments are not supported.")


@multiplying
def summing(x): return sum(x)

print(summing(range(10)))
# 45


@multiplying()
def summing(x): return sum(x)

print(summing(range(10)))
# 45


@multiplying(factor=10)
def summing(x): return sum(x)

print(summing(range(10)))
# 450


@multiplying(10)
def summing(x): return sum(x)
print(summing(range(10)))
# RuntimeWarning Traceback (most recent call last)
#    ....
# RuntimeWarning: Positional arguments are not supported.

(部分改编自@ShitalShah的回答)

假设你有一个函数

def f(*args):
    print(*args)

你想要添加一个接受参数的装饰器,就像这样:

@decorator(msg='hello')
def f(*args):
    print(*args)

这意味着Python将对f进行如下修改:

f = decorator(msg='hello')(f)

因此,部件装饰器(msg='hello')的返回值应该是一个包装器函数,它接受函数f并返回修改后的函数。然后可以执行修改后的函数。

def decorator(**kwargs):
    def wrap(f):
        def modified_f(*args):
            print(kwargs['msg']) # use passed arguments to the decorator
            return f(*args)
        return modified_f
    return wrap

所以,当你调用f时,就像你在做: 装饰(味精= '你好')(f) (args) === wrap(f)(args) === modified_f(args) 但是modified_f可以访问传递给装饰器的kwargs

的输出

f(1,2,3)

将会是:

hello
(1, 2, 3)

如果函数和装饰器都必须接受参数,可以采用下面的方法。

例如,有一个名为decorator1的装饰器,它接受一个参数

@decorator1(5)
def func1(arg1, arg2):
    print (arg1, arg2)

func1(1, 2)

现在,如果decorator1参数必须是动态的,或者在调用函数时传递,

def func1(arg1, arg2):
    print (arg1, arg2)


a = 1
b = 2
seconds = 10

decorator1(seconds)(func1)(a, b)

在上面的代码中

Seconds是decorator1的参数 A b是func1的参数

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

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

在这里你可以读到更多关于这个主题的内容——也可以使用可调用对象来实现这个功能,这里也有解释。