问题
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