我对python及其概念有点新鲜。对于我目前的项目,我需要以x rate / y分钟进行某些api调用。 关于这一点,我遇到了装饰器的概念和相同的python库。 它被称为ratelimit并点击here转到其github链接
这个api最简单的例子是:
from ratelimit import rate_limited
import requests
MESSAGES=100
SECONDS= 3600
@rate_limited(MESSAGES, SECONDS)
def call_api(url):
response = requests.get(url)
if response.status_code != 200:
raise ApiError('Cannot call API: {}'.format(response.status_code))
return response
但我需要从另一个函数
调用此函数call_apidef send_message():
global MESSAGES
global SECONDS
MESSAGES=10
SECONDS=5
end_time=time.time()+60 #the end time is 60 seconds from the start time
while(time.time()<end_time):
call_api(url)
我希望调用发生,并希望装饰器的参数在运行时更新,因为实际值将是用户输入。 但根据我的理解,装饰器在运行时之前取值。那么如何将动态值传递给装饰器。
Thanx提前帮助
答案 0 :(得分:1)
装饰器可以随时使用,而不仅仅是在定义函数时。您无法使用装饰器语法。
# undecorated
def call_api(url):
response = requests.get(url)
if response.status_code != 200:
raise ApiError('Cannot call API: {}'.format(response.status_code))
return response
def send_message():
global MESSAGES
global SECONDS
MESSAGES=10
SECONDS=5
end_time=time.time()+60 #the end time is 60 seconds from the start time
rl_api = rate_limited(MESSAGES, SECONDS)(call_api)
while(time.time()<end_time):
rl_api(url)
这意味着您可以使用rate_limited
的不同参数同时创建多个速率限制函数。
fast_api = rate_limited(100, 5)(call_api)
slow_api = rate_limited(10, 5)(call_api)
答案 1 :(得分:0)
你的问题基本上是你是否可以通过引用而不是通过值来调用装饰器。答案是yes。执行摘要:传递一个可变对象。
在这种特殊情况下,它对你没有任何好处。正如您在ratelimit
模块的code中所看到的,every
和period
这两个参数用于设置新变量frequency
,当定义装饰函数时:
frequency = abs(every) / float(clamp(period))
要获得可变频率,您必须重写模块以支持您的需求,但这应该是可行的。请将以下内容视为最小的插图:
def limit(limiter):
def decorator(func):
def wrapper(*args, **kwargs):
print(limiter.period, limiter.every)
return func(*args, **kwargs)
return wrapper
return decorator
class Limiter():
def __init__(self, every, period):
self.every = every
self.period = period
现在给它一个旋转:
>>> l = Limiter(1, 2)
>>>
>>> @limit(l)
... def foo():
... pass
...
>>> foo()
2 1
>>> l.every = 10
>>> foo()
2 10