Python декоратор для разбора, включая аргументы функции - PullRequest
0 голосов
/ 28 апреля 2020

Как можно написать декоратор 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
...