我正在构建一个API的包装器,它要求每次调用之间至少等待1秒钟。我想我可以通过以下方式使用装饰器来解决这个问题:
import datetime, time
last_time = datetime.datetime(2014, 1, 1)
def interval_assurer(f):
global last_time
if (datetime.datetime.now() - last_time).seconds < 1:
print("Too fast...")
time.sleep(1)
last_time = datetime.datetime.now()
return f
@interval_assurer
def post():
pass
由于某种原因,这不会起作用,我不知道为什么。 last_time
第一次调用post
时会更新,但之后不会更新。请记住,这是我第一次尝试装饰器,所以我可能遗漏了一些基本的东西。
感谢。
答案 0 :(得分:4)
由于你的interval_assurer
是装饰者,所以它只调用一次:定义函数时,而不是调用函数时。您需要创建一个这样的包装函数:
import time, functools
def interval_assurer(f):
last_time = [0]
@functools.wraps(f) # optional, but nice to have
def wrapper(*args, **kwargs):
time_diff = time.time() - last_time[0]
if time_diff < 1:
print("Too fast...")
time.sleep(1 - time_diff)
last_time[0] = time.time()
return f(*args, **kwargs)
return wrapper
@interval_assurer
def post(self, **kwargs):
pass
你也不需要全局(在Python 3中,列表的技巧可以用nonlocal
代替)。
答案 1 :(得分:2)
装饰器函数只返回原始函数,因此定时代码仅在调用装饰器时运行,即在评估函数定义时。相反,它应该返回包含时序代码的新函数,并在适当时调用f
。
尝试类似:
def interval_assurer(f):
def func():
global last_time
if (datetime.datetime.now() - last_time).seconds < 1:
print("Too fast...")
time.sleep(1)
last_time = datetime.datetime.now()
return f()
return func
如果您的装饰函数需要参数,则应在*args, **kwargs
的定义中包含func
并调用f
;另外,请考虑依次使用functools.wraps(f)
装饰func
。
在@bereal的答案的基础上,您可以使last_time
包装函数的属性删除global
(允许多个包装函数,每个函数都有自己的计时器),以及甚至让一个装饰器接受间隔的参数来强制执行:
import functools
import time
def interval_assured(interval):
"""Ensure consecutive calls are separated by a minimal interval."""
def wrapper(f):
@functools.wraps(f)
def func(*args, **kwargs):
if (time.time() - func.last_time) < interval:
time.sleep(interval)
result = f(*args, **kwargs)
func.last_time = time.time()
return result
func.last_time = time.time()
return func
return wrapper
注意在调用包装函数f
之后重置时间 - 如果f
的运行时为相对于间隔而言很大。
使用中:
>>> def testing(x):
print time.time()
print x
>>> for x in range(3):
testing(x)
1405938405.97
0
1405938406.01
1
1405938406.02
2
>>> @interval_assured(5)
def testing(x):
print time.time()
print x
>>> for x in range(3):
testing(x)
1405938429.71
0
1405938434.73
1
1405938439.75
2