python 39 lines · 6 steps

A thread-safe debounce decorator in Python

A decorator that delays a function until calls stop arriving, using a lock and a restartable timer.

Explained by highlit
1import threading
2from functools import wraps
3 
4 
5def debounce(wait):
6 def decorator(fn):
7 lock = threading.Lock()
8 state = {"timer": None}
9 
10 @wraps(fn)
11 def wrapper(*args, **kwargs):
12 def call():
13 with lock:
14 state["timer"] = None
15 fn(*args, **kwargs)
16 
17 with lock:
18 if state["timer"] is not None:
19 state["timer"].cancel()
20 state["timer"] = threading.Timer(wait, call)
21 state["timer"].daemon = True
22 state["timer"].start()
23 
24 def cancel():
25 with lock:
26 if state["timer"] is not None:
27 state["timer"].cancel()
28 state["timer"] = None
29 
30 wrapper.cancel = cancel
31 return wrapper
32 
33 return decorator
34 
35 
36@debounce(0.3)
37def on_search_input(query):
38 results = search_index.query(query)
39 render(results)
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Debouncing collapses a burst of rapid calls into one execution after the activity settles.
  2. 2A shared mutable dict plus a lock lets nested closures coordinate state safely across threads.
  3. 3Attaching a method to the returned wrapper extends a decorated function without changing its signature.

Related explainers

Share this explainer

Here's the card — post it anywhere.

A thread-safe debounce decorator in Python — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code