Поддерживают ли классы Python такие события, как другие языки? - PullRequest
3 голосов
/ 28 мая 2011

Я работаю над своим первым проектом на Python, и мне уже не хватает событий в моих классах. Возможно, это даже не называется событиями в Python, но я хотел бы создать «группы» в моих классах, к которым можно добавлять ссылки на функции. В какой-то момент в моем классе все ссылки на функции в моей группе будут выполнены.

Это встроено в Python? (Сейчас пользуюсь 2.7)

Ответы [ 2 ]

8 голосов
/ 28 мая 2011

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
1 голос
/ 17 июля 2019

Хотя ответ Джереми Бэнкса работает просто отлично, это не то, что большинство назвало бы «питоническим».Поскольку этот вопрос довольно легко возникает в поисковых системах, вот альтернативный ответ, который пытается использовать лучшие соглашения из моего опыта:

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)

Конечно, обычно плохая идея смешивать события уровня класса и экземпляра, как это, я сделал это только для демонстрационных целей.Если не уверены, используйте события уровня экземпляра.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...