Python: обратные вызовы, делегаты, ...? Что общего? - PullRequest
23 голосов
/ 14 января 2009

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

Ответы [ 8 ]

18 голосов
/ 14 января 2009

Лично я не вижу разницы между обратными вызовами, слушателями и делегатами.

Шаблон наблюдателя (прослушиватели a.k.a, «множественные обратные вызовы» a.k.a) прост в реализации - достаточно просто сохранить список наблюдателей, добавить или удалить из него вызываемые элементы. Этими вызываемыми объектами могут быть функции, связанные методы или классы с магическим методом __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)
2 голосов
/ 14 января 2009

Я не могу говорить об общих подходах, но эта страница (фактическая копия недоступна) имеет реализацию шаблона наблюдателя, который мне нравится.

Вот ссылка на Интернет-архив: http://web.archive.org/web/20060612061259/http://www.suttoncourtenay.org.uk/duncan/accu/pythonpatterns.html

1 голос
/ 14 января 2009

Большинство библиотек Python, которые я использовал, реализуют модель обратного вызова для своих уведомлений о событиях, которая, как мне кажется, вполне подходит для языка. Pygtk делает это, выводя все объекты из GObject , который реализует обработку сигналов на основе обратного вызова. (Хотя это особенность базовой реализации C GTK, а не что-то вдохновленное языком.) Однако, Pygtkmvc делает интересную работу по реализации шаблона наблюдателя (и MVC) поверх Pygtk. Он использует очень богатую реализацию на основе метаклассов, но я обнаружил, что в большинстве случаев он работает довольно хорошо. Код также достаточно прост, чтобы следовать, если вам интересно увидеть один из способов, которым это было сделано.

1 голос
/ 14 января 2009

Все зависит от уровня сложности вашего приложения. Для простых событий обратные вызовы, вероятно, подойдут. Для более сложных шаблонов и разделенных уровней вы должны использовать какую-то реализацию публикации-подписки, например PyDispatcher или pubsub wxPython.

См. Также это обсуждение .

0 голосов
/ 12 мая 2009

Я ищу реализацию для регистрации и обработки событий в Python. Мой единственный опыт работы с Gobject , но я использовал его только с PyGtk. Это гибкий, но может быть слишком сложным для некоторых пользователей. Я также сталкивался с несколькими другими интересными кандидатами, но не ясно, насколько точно они сравниваются друг с другом.

0 голосов
/ 15 января 2009

Модуль 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. Я предлагаю вам просто скопировать и вставить класс в ваш собственный модуль из исходного кода .

0 голосов
/ 14 января 2009

Я видел, как использовались слушатели и обратные вызовы. Но у AFAIK нет пути Python. Они должны быть в равной степени осуществимы, если рассматриваемое приложение подходит.

0 голосов
/ 14 января 2009

Лично я видел только обратные вызовы. Тем не менее, я не видел такого большого количества событийно-управляемого Python-кода, поэтому YMMV.

...