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

当前回答

下面是一个使用带有参数的装饰器的Flask示例。假设我们有一个路由'/user/name',我们想要映射到他的主页。

def matchR(dirPath):
    def decorator(func):
        def wrapper(msg):
            if dirPath[0:6] == '/user/':
                print(f"User route '{dirPath}' match, calling func {func}")
                name = dirPath[6:]
                return func(msg2=name, msg3=msg)
            else:
                print(f"Input dirPath '{dirPath}' does not match route '/user/'")
                return
        return  wrapper
    return decorator

#@matchR('/Morgan_Hills')
@matchR('/user/Morgan_Hills')
def home(**kwMsgs):
    for arg in kwMsgs:
        if arg == 'msg2':
            print(f"In home({arg}): Hello {kwMsgs[arg]}, welcome home!")
        if arg == 'msg3':
            print(f"In home({arg}): {kwMsgs[arg]}")

home('This is your profile rendered as in index.html.')

输出:

User route '/user/Morgan_Hills' match, calling func <function home at 0x000001DD5FDCD310>
In home(msg2): Hello Morgan_Hills, welcome home!
In home(msg3): This is your profile rendered as in index.html.

其他回答

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


下面是函数的装饰器,它在进入和退出函数时输出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} 离开酒吧

就这么简单

def real_decorator(any_number_of_arguments):
   def pseudo_decorator(function_to_be_decorated):

       def real_wrapper(function_arguments):
           print(function_arguments)
           result = function_to_be_decorated(any_number_of_arguments)
           return result

       return real_wrapper
   return pseudo_decorator

Now

@real_decorator(any_number_of_arguments)
def some_function(function_arguments):
        return "Any"

例如,我在下面创建了multiply(),它可以接受一个参数或不接受参数,也可以不接受装饰器的括号,我在下面创建了sum():

from numbers import Number

def multiply(num=1):
    def _multiply(func):
        def core(*args, **kwargs):
            result = func(*args, **kwargs)
            if isinstance(num, Number):
                return result * num
            else:
                return result
        return core
    if callable(num):
        return _multiply(num)
    else:
        return _multiply

def sum(num1, num2):
    return num1 + num2

现在,我把@multiply(5)放在sum()上,然后调用sum(4,6),如下所示:

# (4 + 6) x 5 = 50

@multiply(5) # Here
def sum(num1, num2):
    return num1 + num2

result = sum(4, 6)
print(result)

那么,我可以得到如下结果:

50

接下来,我把@multiply()放在sum()上,然后调用sum(4,6),如下所示:

# (4 + 6) x 1 = 10

@multiply() # Here
def sum(num1, num2):
    return num1 + num2
    
result = sum(4, 6)
print(result)

或者,我把@multiply放在sum()上,然后调用sum(4,6),如下所示:

# 4 + 6 = 10

@multiply # Here
def sum(num1, num2):
    return num1 + num2
    
result = sum(4, 6)
print(result)

那么,我可以得到如下结果:

10

我想展示一个想法,在我看来很优雅。t.dubrownik提出的解决方案显示了一个始终相同的模式:无论装饰器做什么,您都需要三层包装器。

所以我认为这是一个元装饰师的工作,也就是说,装饰师的装饰师。由于decorator是一个函数,它实际上是一个带有参数的常规decorator:

def parametrized(dec):
    def layer(*args, **kwargs):
        def repl(f):
            return dec(f, *args, **kwargs)
        return repl
    return layer

这可以应用于常规的装饰器,以便添加参数。例如,我们有一个decorator,它将一个函数的结果加倍:

def double(f):
    def aux(*xs, **kws):
        return 2 * f(*xs, **kws)
    return aux

@double
def function(a):
    return 10 + a

print function(3)    # Prints 26, namely 2 * (10 + 3)

使用@ parameterized,我们可以构建一个带参数的通用@multiply装饰器

@parametrized
def multiply(f, n):
    def aux(*xs, **kws):
        return n * f(*xs, **kws)
    return aux

@multiply(2)
def function(a):
    return 10 + a

print function(3)    # Prints 26

@multiply(3)
def function_again(a):
    return 10 + a

print function(3)          # Keeps printing 26
print function_again(3)    # Prints 39, namely 3 * (10 + 3)

通常,参数化装饰器的第一个参数是函数,而其余参数将对应于参数化装饰器的参数。

一个有趣的用法示例可以是类型安全的断言装饰器:

import itertools as it

@parametrized
def types(f, *types):
    def rep(*args):
        for a, t, n in zip(args, types, it.count()):
            if type(a) is not t:
                raise TypeError('Value %d has not type %s. %s instead' %
                    (n, t, type(a))
                )
        return f(*args)
    return rep

@types(str, int)  # arg1 is str, arg2 is int
def string_multiply(text, times):
    return text * times

print(string_multiply('hello', 3))    # Prints hellohellohello
print(string_multiply(3, 3))          # Fails miserably with TypeError

最后注意:这里我没有使用functools。包装器函数,但我建议始终使用它。

在我的实例中,我决定通过一行lambda来解决这个问题,以创建一个新的decorator函数:

def finished_message(function, message="Finished!"):

    def wrapper(*args, **kwargs):
        output = function(*args,**kwargs)
        print(message)
        return output

    return wrapper

@finished_message
def func():
    pass

my_finished_message = lambda f: finished_message(f, "All Done!")

@my_finished_message
def my_func():
    pass

if __name__ == '__main__':
    func()
    my_func()

执行时,输出:

Finished!
All Done!

也许不像其他解决方案那样可扩展,但对我来说是可行的。