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

当前回答

定义这个decoratorize函数来生成定制的decorator函数:

def decoratorize(FUN, **kw):
    def foo(*args, **kws):
        return FUN(*args, **kws, **kw)
    return foo

可以这样用:

    @decoratorize(FUN, arg1 = , arg2 = , ...)
    def bar(...):
        ...

其他回答

以下是对t.dubrownik的回答稍加修改的版本。为什么?

作为通用模板,您应该返回原始函数的返回值。 这将改变函数的名称,这可能会影响其他装饰器/代码。

所以使用@functools.wraps():

from functools import wraps

def create_decorator(argument):
    def decorator(function):
        @wraps(function)
        def wrapper(*args, **kwargs):
            funny_stuff()
            something_with_argument(argument)
            retval = function(*args, **kwargs)
            more_funny_stuff()
            return retval
        return wrapper
    return decorator

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

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

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

我认为这里有一个工作的、现实世界的示例,其中包含最通用的用例的使用示例。


下面是函数的装饰器,它在进入和退出函数时输出log。

参数控制是否打印输入输出值,日志级别等。

import logging 
from functools import wraps


def log_in_out(logger=logging.get_logger(), is_print_input=True, is_print_output=True, is_method=True, log_level=logging.DEBUG):
    """
    @param logger-
    @param is_print_input- toggle printing input arguments
    @param is_print_output- toggle printing output values
    @param is_method- True for methods, False for functions. Makes "self" not printed in case of is_print_input==True
    @param log_level-

    @returns- a decorator that logs to logger when entering or exiting the decorated function.
    Don't uglify your code!
    """

    def decor(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            if is_print_input:
                logger.log(
                    msg=f"Entered {fn.__name__} with args={args[1:] if is_method else args}, kwargs={kwargs}",
                    level=log_level
                )
            else:
                logger.log(
                    msg=f"Entered {fn.__name__}",
                    level=log_level
                )

            result = fn(*args, **kwargs)

            if is_print_output and result is not None:
                logger.log(
                    msg=f"Exited {fn.__name__} with result {result}",
                    level=log_level,
                )
            else:
                logger.log(
                    msg=f"Exited {fn.__name__}",
                    level=log_level
                )

            return result

        return wrapper

    return decor

用法:

 @log_in_out(is_method=False, is_print_input=False)
    def foo(a, b=5):
        return 3, a

Foo(2)—>打印

输入foo 输出结果为(3,2)的foo

    class A():
        @log_in_out(is_print_output=False)
        def bar(self, c, m, y):
            return c, 6

a = () A.bar (1,2, y=3)—>打印

输入bar with args=(1, 2), kwargs={y: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的参数

它是一个可以以多种方式调用的装饰器(在python3.7中测试):

import functools


def my_decorator(*args_or_func, **decorator_kwargs):

    def _decorator(func):

        @functools.wraps(func)
        def wrapper(*args, **kwargs):

            if not args_or_func or callable(args_or_func[0]):
                # Here you can set default values for positional arguments
                decorator_args = ()
            else:
                decorator_args = args_or_func

            print(
                "Available inside the wrapper:",
                decorator_args, decorator_kwargs
            )

            # ...
            result = func(*args, **kwargs)
            # ...

            return result

        return wrapper

    return _decorator(args_or_func[0]) \
        if args_or_func and callable(args_or_func[0]) else _decorator


@my_decorator
def func_1(arg): print(arg)

func_1("test")
# Available inside the wrapper: () {}
# test


@my_decorator()
def func_2(arg): print(arg)

func_2("test")
# Available inside the wrapper: () {}
# test


@my_decorator("any arg")
def func_3(arg): print(arg)

func_3("test")
# Available inside the wrapper: ('any arg',) {}
# test


@my_decorator("arg_1", 2, [3, 4, 5], kwarg_1=1, kwarg_2="2")
def func_4(arg): print(arg)

func_4("test")
# Available inside the wrapper: ('arg_1', 2, [3, 4, 5]) {'kwarg_1': 1, 'kwarg_2': '2'}
# test

PS感谢用户@norok2 - https://stackoverflow.com/a/57268935/5353484

UPD装饰器,用于根据注释验证类的函数和方法的参数和/或结果。可用于同步或异步版本:https://github.com/EvgeniyBurdin/valdec