You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python中实现每次事件set都执行绑定函数的机制

Python3 自定义事件系统实现(对齐JS EventTarget逻辑)

原有代码问题说明

threading.Event是Python标准库提供的线程同步原语,并非为事件分发场景设计:它的wait()方法只会阻塞到信号第一次被set(),之后不会自动重置阻塞状态。你写的监听函数仅调用了一次wait(),执行完打印逻辑后函数就直接运行结束,对应子线程随之退出,后续再set()事件自然不会触发执行。

实现方案

方案1:对齐JS原生事件逻辑的通用实现

JS自定义事件的核心能力是:事件实例支持绑定/解绑监听回调,派发事件时按绑定顺序执行所有对应类型的回调。以下是纯标准库实现,接口和JS完全对齐:

from collections import defaultdict
import threading
from typing import Callable, Any

class EventTarget:
    def __init__(self):
        self._listeners: dict[str, list[Callable]] = defaultdict(list)
        self._lock = threading.Lock()

    def addEventListener(self, event_type: str, callback: Callable, useCapture: bool = False) -> None:
        """对齐JS的addEventListener接口,useCapture参数为接口兼容保留,暂不实现事件冒泡/捕获逻辑"""
        with self._lock:
            if callback not in self._listeners[event_type]:
                self._listeners[event_type].append(callback)

    def removeEventListener(self, event_type: str, callback: Callable) -> None:
        """对齐JS的removeEventListener接口"""
        with self._lock:
            if callback in self._listeners[event_type]:
                self._listeners[event_type].remove(callback)

    def dispatchEvent(self, event_type: str, *event_args: Any, **event_kwargs: Any) -> None:
        """对齐JS的dispatchEvent接口,触发事件时将参数传给所有绑定的监听回调"""
        with self._lock:
            callbacks = self._listeners[event_type].copy()
        for cb in callbacks:
            cb(*event_args, **event_kwargs)

对应你给出的JS示例的等价Python写法:

import time

# 等价JS中实现了EventTarget接口的DOM元素elem
elem = EventTarget()
x = 0

# 事件监听回调
def myevent_handler(e=None):
    global x
    print(f"event triggered, x = {x}")
    x += 1

# 绑定事件监听,等价 elem.addEventListener('myevent', function (e) { /* ... */ }, false)
elem.addEventListener('myevent', myevent_handler, False)

# 循环派发事件,等价 elem.dispatchEvent(event)
if __name__ == "__main__":
    while True:
        elem.dispatchEvent('myevent')
        time.sleep(1)

方案2:基于threading.Event的修正版本

如果你需要监听逻辑跑在独立子线程,不阻塞主线程,可以给监听函数加常驻循环,每次收到信号执行完逻辑后清空事件、重新进入等待状态:

import threading
import time

event = threading.Event()
x = 0

def myFunction():
    global x
    while True:
        event.wait()
        event.clear() # 收到信号立刻清空,避免重复触发
        print("event is set : " + str(x))
        x += 1
        time.sleep(0.3)

# 设为守护线程,主线程退出时子线程自动终止
th1 = threading.Thread(target=myFunction, daemon=True)
th1.start()

while True:
    event.set()
    time.sleep(1)

注意:该threading版本仅适合简单场景,存在事件丢失风险:如果子线程还在处理上一次事件、未进入wait状态时主线程调用了set(),本次触发会被直接跳过。生产环境优先使用方案1的EventTarget实现。

内容的提问来源于stack exchange,提问作者noobForever

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 17:03:17