Debounce (Python)

How to create and use a debouncer in Python.

In both of these examples, the inner function won't run until at least DEBOUNCE_TIME seconds has passed.

Standalone

from threading import Timer
import time

DEBOUNCE_TIME = 1  # 1 second
debounced_action = None


def debounce_action(message: str) -> None:
    """ Print the last message to be invoked within a certain amount of time """
    global debounced_action

    def print_message():
        print(message)
    
    if debounced_action:
        debounced_action.cancel()
    debounced_action = Timer(DEBOUNCE_TIME, print_message)
    debounced_action.start()


if __name__ == "__main__":
    debounce_action("Won't print this one")
    time.sleep(.5)
    debounce_action("Or this one")
    time.sleep(.99)
    debounce_action("This one will though!")

The benefit of using this standalone is that you can have multiple items debouncing with the same inner function and different parameters by using a dict to store the different debounced_actions instead of using a singular global.

Decorator

from threading import Timer
import time

DEBOUNCE_TIME = 1


def debounce(wait):
    """ Decorator that will postpone a functions
        execution until after wait seconds
        have elapsed since the last time it was invoked. """
    def decorator(fn):
        def debounced(*args, **kwargs):
            def call_it():
                fn(*args, **kwargs)
            try:
                debounced.t.cancel()
            except(AttributeError):
                pass
            debounced.t = Timer(wait, call_it)
            debounced.t.start()
        return debounced
    return decorator

  
@debounce(DEBOUNCE_TIME)
def print_message(message: str):
    print(message)

    
if __name__ == "__main__":
    print_message("Won't print this one")
    time.sleep(.5)
    print_message("Or this one")
    time.sleep(.99)
    print_message("This one will though!")

The benefit of using a decorator is you can throw it on any function that needs debouncing at it saves you the reuse of the debouncing code in multiple places.

References:

  1. https://gist.github.com/walkermatt/2871026

Last modified: 202401040446