Event Programming¶
Metaclass¶
class EventListener(type):
listeners: dict[str, list[callable]] = {}
@classmethod
def register(cls, *clsnames):
def wrapper(func):
for clsname in clsnames:
if clsname not in cls.listeners:
cls.listeners[clsname] = []
cls.listeners[clsname] += [func]
return wrapper
def __new__(mcs, classname, bases, attrs):
for listener in mcs.listeners.get(classname, []):
listener.__call__(classname, bases, attrs)
return type(classname, bases, attrs)
@EventListener.register('Astronaut')
def hello_class(clsname, bases, attrs):
print(f'\n\nHello new class {clsname}\n')
@EventListener.register('Astronaut', 'Person')
def print_name(clsname, bases, attrs):
print('\nNew class created')
print('Classname:', clsname)
print('Bases:', bases)
print('Attrs:', attrs)
class Person(metaclass=EventListener):
pass
class Astronaut(Person, metaclass=EventListener):
pass
# New class created
# Classname: Person
# Bases: ()
# Attrs: {'__module__': '__main__', '__qualname__': 'Person'}
#
#
# Hello new class Astronaut
#
#
# New class created
# Classname: Astronaut
# Bases: (<class '__main__.Person'>,)
# Attrs: {'__module__': '__main__', '__qualname__': 'Astronaut'}
Implementation¶
class event:
__slots__ = ('__subscribers', )
def __init__(self):
self.__subscribers = set()
def call(self, *args, **kwargs):
for subscriber in self.__subscribers:
subscriber(*args, **kwargs)
__call__ = call
def register(self, function):
self.__subscribers.add(function)
return self
__add__ = __iadd__ = register
def unregister(self, function):
self.__subscribers.remove(function)
return self
__sub__ = __isub__ = unregister
class EventManager:
@staticmethod
def register(name):
if not hasattr(EventManager, name):
setattr(EventManager, name, event())
return getattr(EventManager, name).register
Use Case¶
@EventManager.register('on_foo')
def foo(*args, **kwargs):
print('Args: ' + str(args), 'Kwargs: ' + str(kwargs))
def call_on_foo():
EventManager.on_foo()
EventManager.on_foo(1, 2, 3)
EventManager.on_foo(a=1, b=2, c=3)
EventManager.on_foo(1, 2, 3, a=1, b=2, c=3)
@EventManager.register('on_bar')
def bar():
call_on_foo()
EventManager.on_bar()