Does Python classes support events like other languages?

谁都会走 提交于 2021-01-17 08:57:06

问题


I'm working on my first Python project, and I'm already missing events in my classes. Perhaps it's not even called events in Python, but I would like to create "groups" in my classes to which function references can be added. At some point in my class all function references in my group would execute.

Is this built into Python? (I'm using 2.7 at the moment)


回答1:


Python doesn't have any sort of event system built-in, but it's could be implemented pretty simply. For example:

class ObjectWithEvents(object):
    callbacks = None

    def on(self, event_name, callback):
        if self.callbacks is None:
            self.callbacks = {}

        if event_name not in self.callbacks:
            self.callbacks[event_name] = [callback]
        else:
            self.callbacks[event_name].append(callback)

    def trigger(self, event_name):
        if self.callbacks is not None and event_name in self.callbacks:
            for callback in self.callbacks[event_name]:
                callback(self)

class MyClass(ObjectWithEvents):
    def __init__(self, contents):
        self.contents = contents

    def __str__(self):
        return "MyClass containing " + repr(self.contents)

def echo(value): # because "print" isn't a function...
    print value

o = MyClass("hello world")
o.on("example_event", echo)
o.on("example_event", echo)
o.trigger("example_event") # prints "MyClass containing \"Hello World\"" twice



回答2:


While Jeremy Banks' answer works just fine, it's not what most would call "pythonic". Since this question comes up quite easily through search engines, here's an alternative answer that attemps to use the best conventions from my experience:

class Event:
    def __init__(self):
        self.listeners = []

    def __iadd__(self, listener):
        """Shortcut for using += to add a listener."""
        self.listeners.append(listener)
        return self

    def notify(self, *args, **kwargs):
        for listener in self.listeners:
            listener(*args, **kwargs)

To use it you simply create an Event object and then register listener callbacks by either manipulating the listeners list directly, or using the += shortcut. You then use the notify() method to call all the listeners. Any arguments and keyword arguments passed to the notify() method will be forwarded to the listeners.

Here's a full example:

>>> my_event = Event()
>>> def print_person_info(name, age, sex):
...     print("Hello! I am {}, I'm a {}-year-old {}".format(name, age, sex))
...
>>> my_event += print_person_info
>>> my_event.notify('Markus', 23, 'male')
Hello! I am Markus, I'm a 23-year-old male

These event objects can easily be added to a class or an instance as well:

class Soldier:
    # An event on a class level.
    # Listening to just this will notify you of *any* person dying. 
    e_death = Event()

    def __init__(self, name, health):
        self.name = name
        self.health = health

        # Instance level event.
        # Using this you need to listen to each person separately.
        self.e_eat = Event()

    def eat(self, amount):
        self.health += amount
        self.e_eat.notify(self, amount=amount)

    def hurt(self, damage):
        self.health -= damage
        if self.health <= 0:
            Soldier.e_death.notify(self)

Of course it's usually a bad idea to mix class and instance level events like this, I've only done if for demonstration purposes. If unsure, use the instance level events.




回答3:


In case someone is interested in event support for python version 3+ there is event-notifier library available ( https://pypi.org/project/event-notifier/ )

Also there is also a great observation list of alternatives available here:



来源:https://stackoverflow.com/questions/6158602/does-python-classes-support-events-like-other-languages

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!