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

当前回答

在我的实例中,我决定通过一行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!

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

其他回答

就这么简单

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"

匿名设置中的参数装饰。

在许多可能的“嵌套”语法糖装饰的两种变化中被提出。它们之间的区别在于执行wrt到目标函数的顺序,并且它们的效果通常是独立的(不相互作用)。

装饰器允许在目标函数执行之前或之后“注入”自定义函数。

这两个函数的调用都发生在一个元组中。默认情况下,返回值是目标函数的结果。

语法糖装饰@first_internal(send_msg)('…end')要求版本>= 3.9,请参阅PEP 614放松对装饰器的语法限制。

functools使用。以保留目标函数的文档字符串。

from functools import wraps


def first_external(f_external):
    return lambda *args_external, **kwargs_external:\
           lambda f_target: wraps(f_target)(
               lambda *args_target, **kwargs_target:
                  (f_external(*args_external, **kwargs_external),
                   f_target(*args_target, **kwargs_target))[1]
           )


def first_internal(f_external):
    return lambda *args_external, **kwargs_external:\
           lambda f_target: wraps(f_target)(
               lambda *args_target, **kwargs_target:
                  (f_target(*args_target, **kwargs_target),
                   f_external(*args_external, **kwargs_external))[0]
           )


def send_msg(x):
   print('msg>', x)


@first_internal(send_msg)('...end')    # python >= 3.9
@first_external(send_msg)("start...")  # python >= 3.9
def test_function(x):
    """Test function"""
    print('from test_function')
    return x


test_function(2)

输出

msg> start...
from test_function
msg> ...end

讲话

composition decorators, such as pull-back and push-forward (maybe in a more Computer Science terminology: co- and resp. contra-variant decorator), could more useful but need ad-hoc care, for example composition rules, check which parameters go where, etc syntactic sugar acts as a kind of partial of the target function: once decorated there is no way back (without extra imports) but it is not mandatory, a decorator can be used also in its extended forms, i.e. first_external(send_msg)("start...")(test_function)(2) the results of a workbench with timeit.repeat(..., repeat=5, number=10000) which compare the classical def and lambda decoration shows that are almost equivalent: for lambda: [6.200810984999862, 6.035239247000391, 5.346362481000142, 5.987880147000396, 5.5331550319997405] - mean -> 5.8206 for def: [6.165001932999985, 5.554595884999799, 5.798066574999666, 5.678178028000275, 5.446507932999793] - mean -> 5.7284 naturally an non-anonymous counterpart is possible and provides more flexibility

上面的回答很棒。这个例子还演示了@wraps,它从原始函数中获取文档字符串和函数名,并将其应用于新的包装版本:

from functools import wraps

def decorator_func_with_args(arg1, arg2):
    def decorator(f):
        @wraps(f)
        def wrapper(*args, **kwargs):
            print("Before orginal function with decorator args:", arg1, arg2)
            result = f(*args, **kwargs)
            print("Ran after the orginal function")
            return result
        return wrapper
    return decorator

@decorator_func_with_args("foo", "bar")
def hello(name):
    """A function which prints a greeting to the name provided.
    """
    print('hello ', name)
    return 42

print("Starting script..")
x = hello('Bob')
print("The value of x is:", x)
print("The wrapped functions docstring is:", hello.__doc__)
print("The wrapped functions name is:", hello.__name__)

打印:

Starting script..
Before orginal function with decorator args: foo bar
hello  Bob
Ran after the orginal function
The value of x is: 42
The wrapped functions docstring is: A function which prints a greeting to the name provided.
The wrapped functions name is: hello

假设你有一个函数

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的参数