Могу ли я передать динамическое значение декоратору в Python?
Я немного новичок в Python и его концепции. Для моего текущего проекта мне нужно сделать определенные вызовы 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)
Я хочу, чтобы вызов состоялся, и хочу, чтобы аргументы декоратора обновлялись во время выполнения, поскольку реальные значения будут вводиться пользователем. Но, насколько я понимаю, декоратор принимает значение до запуска. Так как я могу передать динамическое значение декоратору.
Спасибо заранее за помощь
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)
Ваш вопрос заключается в том, можете ли вы вызывать декораторы по ссылке, а не по значению. На это ответ да. Краткое содержание: передать изменяемый объект.
В данном конкретном случае это не принесет вам пользы. Как вы можете видеть в коде для ratelimit
модуль, два параметра, 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