Python 类是否支持像其他语言一样的事件?
我正在做我的第一个Python项目,但我发现我的类里缺少一些事件。也许在Python里不叫事件,但我想在我的类里创建一些“组”,可以把函数的引用放进去。到某个时刻,我希望在我的类里所有在这个组里的函数都能执行。
Python里有这个功能吗?(我现在在用2.7版本)
3 个回答
1
如果有人对Python 3及以上版本的事件支持感兴趣,可以使用一个叫做event-notifier的库,链接在这里:https://pypi.org/project/event-notifier/
另外,这里还有一个很棒的替代方案列表,可以在这里找到:
15
虽然Jeremy Banks的回答很好用,但大多数人可能不会觉得它是“符合Python风格”的。因为这个问题在搜索引擎上很常见,所以我想分享一个我认为更好的做法:
class EventSource:
def __init__(self):
self.listeners = []
def __iadd__(self, listener):
"""Shortcut for using += to add a listener."""
self.listeners.append(listener)
return self
def emit(self, *args, **kwargs):
for listener in self.listeners:
listener(*args, **kwargs)
现在,只需创建一个 EventSource
对象,并通过直接操作 listeners
列表或者使用 +=
这个快捷方式来注册监听器回调。然后,你可以使用 emit()
方法来通知所有的监听器。传递给 emit()
的任何参数和关键字参数都会被转发给监听器。
下面是一个完整的例子:
>>> user_registered = EventSource()
>>> def print_user_info(name, age, sex):
... print(f'Registered {name}, a {age}-year-old {sex}')
...
>>> user_registered += print_user_info
>>> user_registered.emit('Markus', 28, 'male')
Registered Markus, a 23-year-old male
这些事件源也可以很容易地添加到一个类或实例中:
class Soldier:
# An event on a class level.
# Listening to just this will notify you of *any* soldier dying.
died = EventSource()
def __init__(self, name, health):
self.name = name
self.health = health
# Instance level event.
# Using this you need to listen to each soldier separately.
self.ate = EventSource()
def eat(self, amount):
self.health += amount
self.ate.emit(self, amount=amount)
def hurt(self, damage):
self.health -= damage
if self.health <= 0:
Soldier.died.emit(self)
当然,通常把类和实例级别的事件混合在一起并不是个好主意,我这样做只是为了演示。如果不确定,建议使用实例级别的事件。
16
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