Synchronous Dispatching¶
The EventDispatcher class provides synchronous, blocking event dispatching. Use this when your listeners perform regular (non-async) operations.
When to Use EventDispatcher¶
Choose EventDispatcher when:
Your listeners perform synchronous operations (database queries, file I/O, calculations)
You’re working with existing synchronous code
You don’t need async/await functionality
You want simpler, more straightforward code flow
Creating a Dispatcher¶
Create an instance of EventDispatcher:
from whistle import EventDispatcher
dispatcher = EventDispatcher()
All listeners registered with this dispatcher must be regular (synchronous) functions. Attempting to register an async function will raise a TypeError.
Multiple Listeners¶
Multiple listeners can respond to the same event. They execute in the order they were registered (when no priority is specified):
from whistle import EventDispatcher
def main():
"""Demonstrate multiple listeners for a single event."""
dispatcher = EventDispatcher()
# Define multiple listener functions
def turn_off_lights(event):
print("1. Turning off the lights")
def start_music(event):
print("2. Starting the music")
def open_curtains(event):
print("3. Opening the curtains")
# Register all listeners for the same event
dispatcher.add_listener("show.start", turn_off_lights)
dispatcher.add_listener("show.start", start_music)
dispatcher.add_listener("show.start", open_curtains)
# Dispatch the event - all listeners will be called
dispatcher.dispatch("show.start")
if __name__ == "__main__":
main()
Running this example produces:
1. Turning off the lights
2. Starting the music
3. Opening the curtains
All three listeners execute sequentially when the event is dispatched.
Using the @listen Decorator¶
For cleaner code, use the @listen decorator to register listeners:
from whistle import EventDispatcher
def main():
"""Demonstrate listener registration using decorators."""
dispatcher = EventDispatcher()
# Use decorator to register listeners
@dispatcher.listen("user.login")
def on_user_login(event):
print(f"User logged in - event: {event.name}")
@dispatcher.listen("user.logout")
def on_user_logout(event):
print(f"User logged out - event: {event.name}")
# Dispatch events
dispatcher.dispatch("user.login")
dispatcher.dispatch("user.logout")
if __name__ == "__main__":
main()
The decorator provides a more elegant syntax and makes the event-listener relationship clear at the point of definition.
Dispatching Events¶
The dispatch() method triggers an event:
event = dispatcher.dispatch("event.name")
Key behaviors:
If no
Eventobject is provided, the dispatcher creates one automaticallyThe event object is passed to all registered listeners
Listeners execute sequentially in priority order
The event object is returned after all listeners execute
Providing Custom Events¶
You can provide your own event object:
from whistle import Event
custom_event = Event()
custom_event.my_data = "some value"
dispatcher.dispatch("event.name", custom_event)
Listeners can then access event.my_data. See Custom Event Classes for more details on creating custom event classes.
API Summary¶
EventDispatcher provides:
add_listener(event_id, listener, priority=0): Register a listenerremove_listener(event_id, listener): Unregister a listenerlisten(event_id, priority=0): Decorator for registering listenersdispatch(event_id, event=None): Trigger an event synchronouslyget_listeners(event_id=None): Retrieve registered listenershas_listeners(event_id=None): Check if listeners are registered
See also Asynchronous Dispatching for the async equivalent.