Events in Python
Introduction
Event-driven programming is essential for building responsive, decoupled applications: instead of calling functions directly, the system emits “events” and listeners react to them. While Python doesn’t include a native event system as structured as languages like C# or MATLAB, it’s straightforward to implement one from scratch or leverage external libraries for a robust solution.
1. Fundamental concepts
- Event: an observable action within the application (mouse click, key press, state change).
- Listener (or event handler): a function that executes when a specific event occurs.
- Dispatcher/Emitter: the component responsible for registering listeners and notifying them when an event fires.
This pattern separates the component that triggers the action from the components that respond, improving modularity and maintainability.
2. Basic implementation with an EventDispatcher
A simple custom dispatcher can:
- Maintain a list of registered listeners.
- Allow adding or removing listeners.
- Notify all listeners when an event is triggered.
class EventDispatcher:
def __init__(self):
self._listeners = []
def add_listener(self, listener):
"""Register a new listener."""
self._listeners.append(listener)
def remove_listener(self, listener):
"""Unregister an existing listener."""
if listener in self._listeners:
self._listeners.remove(listener)
def trigger_event(self, event_data=None):
"""Fire the event, passing event_data to every listener."""
for listener in self._listeners:
listener(event_data)
# Usage example
def my_listener(data):
print("Received event with data:", data)
dispatcher = EventDispatcher()
dispatcher.add_listener(my_listener)
dispatcher.trigger_event("Hello, World!")How it works:
- Instantiate
EventDispatcher. - Register
my_listener. - Call
trigger_event, which loops through all listeners and supplies them with theevent_data.
3. Leveraging the pyee library
For more advanced features (one-time listeners, inheritance of emitters, built-in error handling, or asynchronous events), using pyee is recommended.
Get Ildeberto de los Santos Ruiz’s stories in your inbox
Join Medium for free to get updates from this writer.
1. Install:
pip install pyee2. Example with EventEmitter.
from pyee import EventEmitter
ee = EventEmitter()
@ee.on('click-event')
def handle_click(data):
print("Clicked at:", data)
ee.emit('click-event', {'x': 100, 'y': 200})- The decorator
@ee.on('click-event')bindshandle_clickas a listener. - When
ee.emit(...)is called, all registered handlers run with the provided arguments.
Benefits of pyee:
- Support for once-only listeners (
once). - Native integration with
asynciofor asynchronous event emission. - Cleaner API for complex event workflows.
4. GUI event handling in tkinter
In graphical interfaces, event-driven programming is the standard. With tkinter, handlers are attached to widgets via parameters like command or the bind method.
import tkinter as tk
def on_button_click():
print("Button pressed")
root = tk.Tk()
root.title("Simple App")
root.geometry("300x200")
button = tk.Button(root, text="Click Me", command=on_button_click)
button.pack()
root.mainloop()- Clicking the button invokes
on_button_click. - To capture other events (e.g., key presses), use:
root.bind("<KeyPress>", lambda e: print(f"Key {e.keysym} pressed"))Conclusion and next steps
This tutorial covered:
- Building a custom
EventDispatcherin pure Python. - Adopting the pyee library for richer event systems.
- Managing user interactions in GUI applications with tkinter.
Future articles might explore:
- Asynchronous event emission with
asyncioandpyee. - Event filtering, transformation, and prioritization patterns.
- Event systems in other GUI frameworks (PyQt, Kivy).
Using these patterns, any developer can design reactive, decoupled applications — from simple scripts to large-scale production systems.
Enjoyed this post? Follow my Medium profile to stay up‑to‑date with all my upcoming articles!









