Skip to content

Repository files navigation

C#-Style Event Handling Mechanism for Python

pypistatusdownloadspythonlicense
buildissuespull requests

C# provides a very simple syntax using the observer pattern for its event handling system. The aim of this project is to implement the pattern in python as similarly as possible.

In C#, an "event" is a field or a property of the delegate type EventHandler. Since delegates in C# can be combined and removed with += and -= operators, event handlers can easily subscribe to or unsubscribe from the event using those operators.

Python does not support an addition of two Callable types. So the Event[**TArgs] class is provided to mimic delegates:

fromeventsimportEventitem_changed=Event[str, object]()

C# naming convention prefers present/past participles (changing/changed) instead of on+infinitive (on_change) for events.

Handlers can subscribe to and unsubscribe from the event with the same syntax:

defitem_changed_handler(key: str, value: object) ->None:
...
item_changed+=item_changed_handleritem_changed-=item_changed_handler

An event can be raised by simply invoking it with the arguments:

item_changed("info", obj)

Since Event acts just like a delegate from C#, it is not required to be bound to a class or an instance object. This is the major difference to other packages that try to implement the C#-style event system, which usually revolve around a container object for events.

An example class with event fields may look like this:

classEventExample:
def__init__(self) ->None:
self.__value=""self.updated: Event[str] =Event()
defupdate(self, value: str) ->None:
ifself.__value!=value:
self.__value=valueself.updated(value)
obj=EventExample()
obj.updated+=lambdavalue: print(f"obj.{value=}")
obj.update("new value")

A class decorator @events is provided as a shortcut for event fields:

fromeventsimportEvent, events@eventsclassEventFieldsExample:
item_added: Event[object]
item_removed: Event[object]
item_updated: Event[str, object]

C# also provides event properties with add and remove accessors:

publiceventEventHandler<ItemChangedEventArgs> ItemChanged
{add{ ...}remove{ ...}}

This feature is useful for classes that do not actually own the events, but need to forward the subscriptions to the underlying object that do own the events.

The @event[**TArgs] decorator is provided to support this feature:

fromeventsimportaccessors, event, EventHandlerclassEventPropertyExample:
@event[str, object]defitem_changed():
defadd(self: Self, value: EventHandler[str, object]) ->None: ...
defremove(self: Self, value: EventHandler[str, object]) ->None: ...
return (add, remove)

Note: This is an experimental syntax, and may change in later versions.

Furthermore, the EventHandlerCollection interface is provided to support the functionalities of System.ComponentModel.EventHandlerList class from C#, along with the two implementations EventHandlerList and EventHandlerDict using a linked list and a dictionary respectively. The behaviour of EventHandlerList is exactly the same as of its counterpart from C#.

A typical usage of EventHandlerList in C# can be translated directly into the python code:

classEventPropertyExample:
def__init__(self) ->None:
self.__events=EventHandlerList()
@event# [str, object] is inferreddefitem_changed():
defadd(self: Self, value: EventHandler[str, object]) ->None:
self.__events.add_handler("item_changed", value)
defremove(self: Self, value: EventHandler[str, object]) ->None:
self.__events.remove_handler("item_changed", value)
return (add, remove)
def_on_item_changed(self, key: str, value: object) ->None:
handler=self.__events["item_changed"]
ifhandler:
handler(key, value)

The class decorator @events also provides a shortcut for event properties. The above code can be shortened to:

@events(collection="__events")classEventPropertyExample:
item_changed: event[str, object]
def__init__(self) ->None:
self.__events=EventHandlerList()
def_on_item_changed(self, key: str, value: object) ->None:
self.__events.invoke("item_changed", key, value)

Installation

Install using pip:

pip install cs-events

About

C#-Style Event Handling Mechanism for Python

Topics

Resources

Stars

4 stars

Watchers

2 watching

Forks

Releases

Used by

Contributors

Languages