我有一个由装饰器转移变量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
以下是对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
在这里你可以读到更多关于这个主题的内容——也可以使用可调用对象来实现这个功能,这里也有解释。
这是一个函数装饰器模板,如果没有参数,则不需要(),并且支持位置参数和关键字参数(但需要检查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的回答)
在我的实例中,我决定通过一行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!
也许不像其他解决方案那样可扩展,但对我来说是可行的。
我猜你的问题是把参数传递给你的装饰师。这有点棘手,不简单。
下面是一个如何做到这一点的例子:
class MyDec(object):
def __init__(self,flag):
self.flag = flag
def __call__(self, original_func):
decorator_self = self
def wrappee( *args, **kwargs):
print 'in decorator before wrapee with flag ',decorator_self.flag
original_func(*args,**kwargs)
print 'in decorator after wrapee with flag ',decorator_self.flag
return wrappee
@MyDec('foo de fa fa')
def bar(a,b,c):
print 'in bar',a,b,c
bar('x','y','z')
打印:
in decorator before wrapee with flag foo de fa fa
in bar x y z
in decorator after wrapee with flag foo de fa fa
详见Bruce Eckel的文章。
带参数的装饰器应该返回一个函数,该函数将接受一个函数,并返回另一个函数
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