Как можно написать декоратор debounce в python, который отсеивает не только вызываемую функцию, но также и аргументы функции / комбинацию используемых аргументов функции?
Удаление отказов означает подавление вызова функции внутри заданный период времени, скажем, вы вызываете функцию 100 раз в течение 1 секунды, но вы хотите, чтобы эта функция запускалась один раз каждые 10 секунд, а функция с декорацией отказов запускала бы функцию один раз через 10 секунд после последнего вызова функции, если не было вызовов новой функции. сделали. Здесь я спрашиваю, как можно отменить вызов функции с указанием c аргументов функции.
Примером может быть отмена дорогостоящего обновления объекта person, такого как:
@debounce(seconds=10)
def update_person(person_id):
# time consuming, expensive op
print('>>Updated person {}'.format(person_id))
Затем произойдет отладка функции, включая аргументы функции:
update_person(person_id=144)
update_person(person_id=144)
update_person(person_id=144)
>>Updated person 144
update_person(person_id=144)
update_person(person_id=355)
>>Updated person 144
>>Updated person 355
Таким образом, вызов функции update_person с тем же идентификатором person_id будет подавлен (отклонен) до тех пор, пока не пройдет 10-секундный интервал отмены вызова без нового вызова функции с тот же person_id.
Есть несколько декораторов debounce, но ни один из них не содержит аргументов функций, например: https://gist.github.com/walkermatt/2871026
Я сделал аналогичный декоратор газа по функциям и Аргументы:
def throttle(s, keep=60):
def decorate(f):
caller = {}
def wrapped(*args, **kwargs):
nonlocal caller
called_args = '{}'.format(*args)
t_ = time.time()
if caller.get(called_args, None) is None or t_ - caller.get(called_args, 0) >= s:
result = f(*args, **kwargs)
caller = {key: val for key, val in caller.items() if t_ - val > keep}
caller[called_args] = t_
return result
# Keep only calls > keep
caller = {key: val for key, val in caller.items() if t_ - val > keep}
caller[called_args] = t_
return wrapped
return decorate
Основной тэкавэй заключается в том, что он сохраняет аргументы функции в вызывающей стороне [named_args]
См. также разницу между газами и дебазами: http://demo.nimius.net/debounce_throttle/
Обновление:
После некоторой обработки с указанным выше декоратором дроссельной заслонки и нарезкой резьбы. Пример времени i На самом деле, я думаю, что это должно работать:
from threading import Timer
from inspect import signature
import time
def debounce(wait):
def decorator(fn):
sig = signature(fn)
caller = {}
def debounced(*args, **kwargs):
nonlocal caller
try:
bound_args = sig.bind(*args, **kwargs)
bound_args.apply_defaults()
called_args = fn.__name__ + str(dict(bound_args.arguments))
except:
called_args = ''
t_ = time.time()
def call_it(key):
try:
# always remove on call
caller.pop(key)
except:
pass
fn(*args, **kwargs)
try:
# Always try to cancel timer
caller[called_args].cancel()
except:
pass
caller[called_args] = Timer(wait, call_it, [called_args])
caller[called_args].start()
return debounced
return decorator