0

So I have this following code:

from collections import defaultdict

_event_handlers = defaultdict(set)


def add_event_handler(event_name=""):
    def wrapper(func):
        _event_handlers[event_name if event_name else func.__name__].add(func)
        return func
    return wrapper


@add_event_handler()
def bar():
    print("test")


class Foo:
    def __init__(self, f):
        self.f = f

    @add_event_handler()
    def bar(self):
        print(self.f)

def dispatch_event(event_name, **kwargs):
    for handler in _event_handlers[event_name]:
        handler(**kwargs)

test = Foo(5)

dispatch_event("bar")

I'm trying to develop an event system which allows you to registered an event with the @add_event_handler() decorator which adds the method to a global _event_handlers variable and then events can be dispatched using that. However, it works for global methods, but not for methods in a class as a TypeError is raised since self is not provided. How can I fix this?

Aspect11
  • 318
  • 1
  • 3
  • 10
  • How do you want this to work? What should be the outcome when you create multiple instances of `Foo()`? – quamrana Apr 28 '23 at 10:33
  • My idea is to have the `_event_handlers` variable be a dictionary with the key being the event name and the value being a set of handlers. So if multiple instances of `Foo` were created, each handler would be added to that set. If there's a better way, I'd be happy to change it though. – Aspect11 Apr 28 '23 at 10:35
  • 1
    The wrapper could return an object which implements `__call__` and `__get__` (see https://docs.python.org/3/howto/descriptor.html ). Then you can at least detect if the object was accessed as attribute of an object instance (with probably following call) or otherwise. – Michael Butscher Apr 28 '23 at 10:37
  • Can you provide an example? I'm not sure what you mean. – Aspect11 Apr 28 '23 at 10:38
  • 1
    Do the answers to this [question](https://stackoverflow.com/questions/63396641/python-class-method-decorator-before-instantiation) help at all? – quamrana Apr 28 '23 at 11:45
  • Those answers do help. Now I just have to figure out how I can have `**kwargs` passed to the events since those answers assume there are no parameters – Aspect11 Apr 28 '23 at 12:06
  • But where would those parameters come from? If they are passed in to `handler()`, then they will just be forwarded to the event. – quamrana Apr 28 '23 at 12:16
  • Thats kinda the point. I want the `dispatch_event` function to have a `**kwargs` parameter which holds the data which is to be used by the events. Then the events can just grab that and use it – Aspect11 Apr 28 '23 at 12:27
  • What `dispatch_event` function? – quamrana Apr 28 '23 at 12:36
  • It would be a function around the for loop. I've just simplified it for now. – Aspect11 Apr 28 '23 at 12:44
  • You'll have to update the question with example code for me to answer that. Or you could ask a new question. – quamrana Apr 28 '23 at 12:56

0 Answers0