-1

我对 python 及其概念有点陌生。对于我当前的项目,我需要以 x 速率/y 分钟进行某些 api 调用。关于这一点,我遇到了装饰器的概念和一个相同的python库。它称为ratelimit并单击此处转到其 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_api

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
    while(time.time()<end_time):
        call_api(url)

我希望调用发生并希望装饰器的参数在运行时更新,因为实际值将是用户输入。但根据我的理解,装饰器在运行时之前取值。那么我如何将动态值传递给装饰器。

提前感谢您的帮助

4

2 回答 2

2

装饰器可以在任何时候使用,而不仅仅是在定义函数时。您只是不能使用装饰器语法

# 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)
于 2018-03-13T15:17:19.380 回答
0

您的问题基本上是您是否可以通过引用而不是按值调用装饰器。对此,答案是肯定的。执行摘要:传递一个可变对象。

在这种特殊情况下,它对你没有任何好处。正如您在模块的代码中看到的ratelimit,两个参数everyperiod用于设置一个新变量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
于 2018-03-13T15:41:08.987 回答