ipywidgets 事件节流

ipywidgets 事件节流#

# 为了保证 `JupyterLite` 可用,需要 notebook 开头添加:
%pip install -q ipywidgets
Note: you may need to restart the kernel to use updated packages.

节流(Throttling)是另一种可用于限制回调的技术。与去抖动不同,去抖动在自上一次(尝试)调用函数以来未经过一定时间时会忽略对函数的调用,而节流则会限制调用的速率。这确保了函数被定期调用。

下面展示了一个同步解决方案。同样地,如果你想使用线程而不是异步编程,你可以用 from threading import Timer 替换 Timer 类。

import asyncio
from time import time

class Timer:
    def __init__(self, timeout, callback):
        self._timeout = timeout
        self._callback = callback

    async def _job(self):
        await asyncio.sleep(self._timeout)
        self._callback()

    def start(self):
        self._task = asyncio.ensure_future(self._job())

    def cancel(self):
        self._task.cancel()

def throttle(wait):
    """ Decorator that prevents a function from being called
        more than once every wait period. """
    def decorator(fn):
        time_of_last_call = 0
        scheduled, timer = False, None
        new_args, new_kwargs = None, None
        def throttled(*args, **kwargs):
            nonlocal new_args, new_kwargs, time_of_last_call, scheduled, timer
            def call_it():
                nonlocal new_args, new_kwargs, time_of_last_call, scheduled, timer
                time_of_last_call = time()
                fn(*new_args, **new_kwargs)
                scheduled = False
            time_since_last_call = time() - time_of_last_call
            new_args, new_kwargs = args, kwargs
            if not scheduled:
                scheduled = True
                new_wait = max(0, wait - time_since_last_call)
                timer = Timer(new_wait, call_it)
                timer.start()
        return throttled
    return decorator

要了解它与去抖动器的行为有何不同,这里是一个相同的滑块示例,其节流值显示在文本框中。注意它在限制回调速率的同时,交互性有多强。

import ipywidgets as widgets
slider = widgets.IntSlider()
text = widgets.IntText()

@throttle(0.2)
def value_changed(change):
    text.value = change.new
slider.observe(value_changed, 'value')

widgets.VBox([slider, text])