Просто хочу знать, как обычно реагируют на события в Python. В других языках есть несколько способов, таких как функции обратного вызова, делегаты, структуры слушателей и так далее. Есть общий способ? Какие существуют языковые концепции или дополнительные модули по умолчанию и какие вы можете порекомендовать?






Лично я видел только обратные вызовы. Однако я не видел такого количества кода Python, управляемого событиями, поэтому YMMV.
Я не могу говорить об общих подходах, но эта страница (фактическая копия недоступна) имеет реализацию шаблона наблюдателя, который мне нравится.
Вот ссылка на Интернет-архив: http://web.archive.org/web/20060612061259/http://www.suttoncourtenay.org.uk/duncan/accu/pythonpatterns.html
Я видел, как используются слушатели и обратные вызовы. Но AFAIK нет способа Python. Они должны быть в равной степени осуществимы, если рассматриваемое приложение подходит.
Лично я не вижу разницы между обратными вызовами, слушателями и делегатами.
образец наблюдателя (он же слушатели, он же «множественные обратные вызовы») легко реализовать - просто храните список наблюдателей и добавляйте или удаляйте из него вызываемые объекты. Эти вызываемые объекты могут быть функциями, связанными методами или классами с магическим методом __call__. Все, что вам нужно сделать, это определить интерфейс, который вы ожидаете от них - например, получают ли они какие-либо параметры.
class Foo(object):
def __init__(self):
self._bar_observers = []
def add_bar_observer(self, observer):
self._bar_observers.append(observer)
def notify_bar(self, param):
for observer in self._bar_observers:
observer(param)
def observer(param):
print "observer(%s)" % param
class Baz(object):
def observer(self, param):
print "Baz.observer(%s)" % param
class CallableClass(object):
def __call__(self, param):
print "CallableClass.__call__(%s)" % param
baz = Baz()
foo = Foo()
foo.add_bar_observer(observer) # function
foo.add_bar_observer(baz.observer) # bound method
foo.add_bar_observer(CallableClass()) # callable instance
foo.notify_bar(3)
@Kevin - добавил пример с __call__. Вы можете узнать больше об этом (и других специальных именах методов) на docs.python.org/reference/datamodel.html
Думаю в вашем обновлении ошибка, SomeCallable() должен читать SomeCallable (сам не уверен, что исправлю сам, при необходимости удалю комментарий)
@Kevin - я считаю, что с обновлением все в порядке (и работает). Вызываются экземпляры SomeCallable. Я поменяю название класса :)
не могли бы вы объяснить, почему вы унаследовали от объекта? и как метод notify_bar знает, какую функцию / метод наблюдателя он вызывает?
@Lucky, унаследованный от object, - это древняя причуда python2, гарантирующая, что мы получим классы нового стиля вместо классов старого стиля. Необязательно в python3. notify_bar не знает и не заботится о том, какой вызываемый объект вызывает. Раньше он добавлял их в список, а теперь вызывает их. Насколько это возможно, они непрозрачны.
Все зависит от уровня сложности вашего приложения. Для простых событий, вероятно, подойдут обратные вызовы. Для более сложных шаблонов и разделенных уровней вы должны использовать какую-то реализацию публикации-подписки, такую как PyDispatcher или pubsub wxPython.
См. Также это обсуждение.
Большинство библиотек Python, которые я использовал, реализуют модель обратного вызова для своих уведомлений о событиях, что, на мой взгляд, достаточно хорошо подходит для языка. Pygtk делает это, производя все объекты из GObject, который реализует обработку сигналов на основе обратного вызова. (Хотя это особенность базовой реализации C GTK, а не то, что было вдохновлено языком.) Однако Pygtkmvc выполняет интересную работу по реализации шаблона наблюдателя (и MVC) поверх Pygtk. Он использует очень богатую реализацию на основе метаклассов, но я обнаружил, что в большинстве случаев она работает достаточно хорошо. Код достаточно прост для выполнения, если вам интересно увидеть один из способов, которым это было сделано.
Модуль matplotlib.cbook содержит класс CallbackRegistry, на который вы, возможно, захотите взглянуть. Из документация:
Handle registering and disconnecting for a set of signals and
callbacks:
signals = 'eat', 'drink', 'be merry'
def oneat(x):
print 'eat', x
def ondrink(x):
print 'drink', x
callbacks = CallbackRegistry(signals)
ideat = callbacks.connect('eat', oneat)
iddrink = callbacks.connect('drink', ondrink)
#tmp = callbacks.connect('drunk', ondrink) # this will raise a ValueError
callbacks.process('drink', 123) # will call oneat
callbacks.process('eat', 456) # will call ondrink
callbacks.process('be merry', 456) # nothing will be called
callbacks.disconnect(ideat) # disconnect oneat
callbacks.process('eat', 456) # nothing will be called
Вероятно, вам не нужна зависимость от пакета matplotlib. Я предлагаю вам просто скопировать и вставить класс в свой собственный модуль из исходный код.
Я ищу реализацию для регистрации и обработки событий в Python. Мой единственный опыт связан с Gobject, но я использовал его только с PyGtk. Он гибкий, но может быть слишком сложным для некоторых пользователей. Я также встретил несколько других интересных кандидатов, но непонятно, как именно они сравниваются друг с другом.
хороший пример, но как насчет упомянутого вами 'вызов', позволяет ли он регистрировать
foo.add_bar_observer(callable)?