Хотя ответ Джереми Бэнкса работает просто отлично, это не то, что большинство назвало бы «питоническим».Поскольку этот вопрос довольно легко возникает в поисковых системах, вот альтернативный ответ, который пытается использовать лучшие соглашения из моего опыта:
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:
Person.e_death.notify(self)
Конечно, обычно плохая идея смешивать события уровня класса и экземпляра, как это, я сделал это только для демонстрационных целей.Если не уверены, используйте события уровня экземпляра.