Python自定义事件实现与应用
在 Python 中,实现自定义事件和事件发送主要依赖于面向对象编程和设计模式(如 观察者模式)。下面我将从基础实现到高级用法逐步讲解,并附上代码示例。
一、基础概念
事件驱动编程 的核心是:
- 事件 (Event):表示某种动作或状态变化(如鼠标点击、数据到达)
- 事件发送者 (Emitter):触发事件的对象
- 事件监听者 (Listener):订阅并处理事件的对象
二、基础实现(不使用第三方库)
1. 简单事件管理器类
class EventManager:
def __init__(self):
self._event_handlers = {}
def register_event(self, event_name, handler):
"""注册事件监听器"""
if event_name not in self._event_handlers:
self._event_handlers[event_name] = []
self._event_handlers[event_name].append(handler)
def trigger_event(self, event_name, *args, **kwargs):
"""触发事件"""
handlers = self._event_handlers.get(event_name, [])
for handler in handlers:
handler(*args, **kwargs)
# 使用示例
def on_click(x, y):
print(f"Clicked at ({x}, {y})")
manager = EventManager()
manager.register_event("click", on_click)
manager.trigger_event("click", 100, 200) # 输出: Clicked at (100, 200)
2. 带参数的事件对象
class Event:
def __init__(self, name, **kwargs):
self.name = name
self.data = kwargs
class AdvancedEventManager:
def __init__(self):
self._listeners = {}
def add_listener(self, event_name, callback):
self._listeners.setdefault(event_name, []).append(callback)
def dispatch(self, event):
for callback in self._listeners.get(event.name, []):
callback(event)
# 使用示例
def handle_login(event):
print(f"User {event.data['username']} logged in")
manager = AdvancedEventManager()
manager.add_listener("user_login", handle_login)
login_event = Event("user_login", username="john", ip="192.168.1.1")
manager.dispatch(login_event) # 输出: User john logged in
三、使用第三方库(推荐)
1. 使用 PyPubSub
安装库:
pip install pypubsub
示例代码:
from pubsub import pub
# 定义监听函数
def on_data_received(data):
print(f"Received data: {data}")
# 订阅事件
pub.subscribe(on_data_received, 'data_channel')
# 发送事件
pub.sendMessage('data_channel', data=[1, 2, 3])
# 带多个参数
def on_multi_params(name, age):
print(f"{name} is {age} years old")
pub.subscribe(on_multi_params, 'user_info')
pub.sendMessage('user_info', name="Alice", age=25)
2. 使用 blinker(Flask 使用的基础库)
安装:
pip install blinker
示例:
from blinker import Signal
# 创建信号
data_ready = Signal('data-ready')
# 注册接收器
@data_ready.connect
def handle_data(sender, **kwargs):
print(f"Data from {sender}: {kwargs['data']}")
# 发送信号
data_ready.send('server1', data={'temp': 36.5})
四、高级技巧
1. 异步事件处理
结合 asyncio 实现异步事件:
import asyncio
class AsyncEventManager:
def __init__(self):
self._events = {}
def register(self, event_name, coro):
self._events.setdefault(event_name, []).append(coro)
async def trigger(self, event_name, *args):
coros = self._events.get(event_name, [])
await asyncio.gather(*(coro(*args) for coro in coros))
# 使用示例
async def send_email(user):
print(f"Sending email to {user}...")
await asyncio.sleep(1)
manager = AsyncEventManager()
manager.register("user_registered", send_email)
async def main():
await manager.trigger("user_registered", "alice@example.com")
asyncio.run(main())
2. 类型化事件(Python 3.12+ 使用类型标注)
from typing import Protocol, Any
class Event(Protocol):
name: str
data: dict[str, Any]
class UserLoginEvent:
def __init__(self, username: str):
self.name = "user_login"
self.data = {"username": username}
def handle_user_login(event: UserLoginEvent):
print(f"Handle login: {event.data['username']}")
# 类型检查工具会验证事件类型
五、应用场景
- GUI 开发(按钮点击事件)
- 游戏开发(角色受伤事件)
- 微服务通信(消息通知)
- 插件系统(扩展点事件)
六、设计原则
- 松耦合:事件发送者不需要知道监听者的存在
- 单一职责:每个事件处理函数只做一件事
- 可扩展性:方便添加新事件类型和处理程序
- 错误隔离:某个事件处理失败不应影响其他处理程序
根据项目复杂度选择实现方式:小型项目可以用基础实现,大型项目推荐使用 PyPubSub 或 blinker 等成熟库。
浙公网安备 33010602011771号