我有一个由装饰器转移变量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(...):
...
这是curry函数的一个很好的用例。
curry函数本质上是延迟函数的调用,直到提供了所有输入。
这可以用于各种事情,如包装器或函数式编程。在本例中,让我们创建一个接受输入的包装器。
我将使用一个简单的包pamda,其中包含一个用于python的curry函数。这可以用作其他函数的包装器。
安装 Pamda:
pip install pamda
创建一个简单的带有两个输入的装饰函数:
@pamda.curry()
def my_decorator(input, func):
print ("Executing Decorator")
print(f"input:{input}")
return func
使用提供给目标函数的第一个输入应用你的装饰器:
@my_decorator('Hi!')
def foo(input):
print('Executing Foo!')
print(f"input:{input}")
执行你的包装函数:
x=foo('Bye!')
把所有东西放在一起:
from pamda import pamda
@pamda.curry()
def my_decorator(input, func):
print ("Executing Decorator")
print(f"input:{input}")
return func
@my_decorator('Hi!')
def foo(input):
print('Executing Foo!')
print(f"input:{input}")
x=foo('Bye!')
将:
Executing Decorator
input:Hi!
Executing Foo!
input:Bye!
它是一个可以以多种方式调用的装饰器(在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
上面的回答很棒。这个例子还演示了@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 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
编写一个带参数和不带参数的装饰器是一个挑战,因为Python在这两种情况下期望完全不同的行为!许多答案都试图解决这个问题,下面是@norok2对答案的改进。具体来说,这种变化消除了locals()的使用。
下面是@norok2给出的相同示例:
import functools
def multiplying(f_py=None, factor=1):
assert callable(f_py) or f_py is None
def _decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
return factor * func(*args, **kwargs)
return wrapper
return _decorator(f_py) if callable(f_py) 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(factor=10)
def summing(x): return sum(x)
print(summing(range(10)))
# 450
玩一下这段代码。
问题是用户必须提供键、值对的参数,而不是位置参数,并且第一个参数是保留的。