我正在处理我的第一个 Python 项目,并且我的课程中已经缺少事件。也许它在 Python 中甚至不被称为事件,但我想在我的类中创建“组”,可以添加函数引用。在我班级的某个时刻,我组中的所有函数引用都会执行。
这是内置在 Python 中的吗?(我目前使用的是 2.7)
我正在处理我的第一个 Python 项目,并且我的课程中已经缺少事件。也许它在 Python 中甚至不被称为事件,但我想在我的类中创建“组”,可以添加函数引用。在我班级的某个时刻,我组中的所有函数引用都会执行。
这是内置在 Python 中的吗?(我目前使用的是 2.7)
Python 没有内置任何类型的事件系统,但它可以非常简单地实现。例如:
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
虽然 Jeremy Banks 的回答效果很好,但这并不是大多数人所说的“pythonic”。由于这个问题很容易通过搜索引擎出现,所以这里有一个替代答案,它尝试使用我经验中的最佳约定:
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)
要使用它,您只需创建一个Event
对象,然后通过listeners
直接操作列表或使用+=
快捷方式来注册侦听器回调。然后,您使用该notify()
方法调用所有侦听器。传递给该方法的任何参数和关键字参数notify()
都将转发给侦听器。
这是一个完整的例子:
>>> 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
这些事件对象也可以很容易地添加到类或实例中:
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)
当然,像这样混合类和实例级别的事件通常是一个坏主意,我只是出于演示目的才这样做。如果不确定,请使用实例级事件。
如果有人对 python 版本 3+ 的事件支持感兴趣,可以使用 event-notifier 库(https://pypi.org/project/event-notifier/)
此外,这里还有一个很棒的替代品观察列表 :