众所周知,以下两段代码几乎等效:
@dec
def foo():
pass foo = dec(foo)
############################################
foo = dec(foo)
一个常见的错误是认为它@
只是隐藏了最左边的参数。
@dec(1, 2, 3)
def foo():
pass
###########################################
foo = dec(foo, 1, 2, 3)
如果上面是这样的话,编写装饰器会容易得多@
。不幸的是,这不是事情的完成方式。
考虑一个装饰器Wait
,它会破坏程序执行几秒钟。如果您未通过等待时间,则默认值为1秒。用例如下所示。
##################################################
@Wait
def print_something(something):
print(something)
##################################################
@Wait(3)
def print_something_else(something_else):
print(something_else)
##################################################
@Wait(delay=3)
def print_something_else(something_else):
print(something_else)
当Wait
具有参数(例如)时@Wait(3)
,将在其他任何事情发生之前Wait(3)
执行调用。
也就是说,以下两段代码是等效的
@Wait(3)
def print_something_else(something_else):
print(something_else)
###############################################
return_value = Wait(3)
@return_value
def print_something_else(something_else):
print(something_else)
这是个问题。
if `Wait` has no arguments:
`Wait` is the decorator.
else: # `Wait` receives arguments
`Wait` is not the decorator itself.
Instead, `Wait` ***returns*** the decorator
一种解决方案如下所示:
让我们从创建以下类开始DelayedDecorator
:
class DelayedDecorator:
def __init__(i, cls, *args, **kwargs):
print("Delayed Decorator __init__", cls, args, kwargs)
i._cls = cls
i._args = args
i._kwargs = kwargs
def __call__(i, func):
print("Delayed Decorator __call__", func)
if not (callable(func)):
import io
with io.StringIO() as ss:
print(
"If only one input, input must be callable",
"Instead, received:",
repr(func),
sep="\n",
file=ss
)
msg = ss.getvalue()
raise TypeError(msg)
return i._cls(func, *i._args, **i._kwargs)
现在我们可以编写如下内容:
dec = DelayedDecorator(Wait, delay=4)
@dec
def delayed_print(something):
print(something)
注意:
dec
不接受多个参数。
dec
仅接受要包装的功能。
导入检查类PolyArgDecoratorMeta(type):def 调用(等待,* args,** kwargs):尝试:arg_count = len(args)if(arg_count == 1):如果callable(args [0]):SuperClass = inspect。 getmro(PolyArgDecoratorMeta)[1] r =超类。呼叫(Wait,args [0])否则:r = DelayedDecorator(等待,* args,** kwargs)否则:r = DelayedDecorator(等待,* args,** kwargs)最后:通过return r
导入时间类Wait(metaclass = PolyArgDecoratorMeta):def init(i,func,delay = 2):i._func = func i._delay = delay
def __call__(i, *args, **kwargs):
time.sleep(i._delay)
r = i._func(*args, **kwargs)
return r
以下两段代码是等效的:
@Wait
def print_something(something):
print (something)
##################################################
def print_something(something):
print(something)
print_something = Wait(print_something)
我们可以"something"
非常缓慢地打印到控制台,如下所示:
print_something("something")
#################################################
@Wait(delay=1)
def print_something_else(something_else):
print(something_else)
##################################################
def print_something_else(something_else):
print(something_else)
dd = DelayedDecorator(Wait, delay=1)
print_something_else = dd(print_something_else)
##################################################
print_something_else("something")
最后说明
它可能看起来像一个大量的代码,但你不必写类DelayedDecorator
和PolyArgDecoratorMeta
每一个时间。您唯一需要亲自编写类似以下内容的代码,这很短:
from PolyArgDecoratorMeta import PolyArgDecoratorMeta
import time
class Wait(metaclass=PolyArgDecoratorMeta):
def __init__(i, func, delay = 2):
i._func = func
i._delay = delay
def __call__(i, *args, **kwargs):
time.sleep(i._delay)
r = i._func(*args, **kwargs)
return r
execute_complete_reservation
需要两个参数,但您要传递一个。装饰器只是将功能包装到其他功能中的语法糖。有关完整的文档,请参见docs.python.org/reference/compound_stmts.html#function。