Python: Callbacks, Delegates, ... ? What is common?

23,454

Solution 1

Personally I don't see a difference between callbacks, listeners, and delegates.

The observer pattern (a.k.a listeners, a.k.a "multiple callbacks") is easy to implement - just hold a list of observers, and add or remove callables from it. These callables can be functions, bound methods, or classes with the __call__ magic method. All you have to do is define the interface you expect from these - e.g. do they receive any parameters.

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)

Solution 2

It all depends on the level of complexity your application requires. For simple events, callbacks will probably do. For more complex patterns and decoupled levels you should use some kind of a publish-subscribe implementation, such as PyDispatcher or wxPython's pubsub.

See also this discussion.

Solution 3

I can't speak for common approaches, but this page (actual copy is unavailable) has an implementation of the observer pattern that I like.

Here's the Internet Archive link: http://web.archive.org/web/20060612061259/http://www.suttoncourtenay.org.uk/duncan/accu/pythonpatterns.html

Solution 4

Most of the Python libraries I have used implement a callback model for their event notifications, which I think suits the language fairly well. Pygtk does this by deriving all objects from GObject, which implements callback-based signal handling. (Although this is a feature of the underlying C GTK implementation, not something inspired by the language.) However, Pygtkmvc does an interesting job of implementing an observer pattern (and MVC) over the top of Pygtk. It uses a very ornate metaclass based implementation, but I have found that it works fairly well for most cases. The code is reasonably straightforward to follow, as well, if you are interested in seeing one way in which this has been done.

Share:
23,454

Related videos on Youtube

okoman
Author by

okoman

Updated on April 06, 2020

Comments

  • okoman
    okoman about 4 years

    Just want to know what's the common way to react on events in python. There are several ways in other languages like callback functions, delegates, listener-structures and so on. Is there a common way? Which default language concepts or additional modules are there and which can you recommend?

  • Kevin
    Kevin about 13 years
    nice example, but what about the 'call' you mention, does it allow to register foo.add_bar_observer(callable) ?
  • orip
    orip about 12 years
    @Kevin - added an example with __call__. You can read more about it (and other special method names) at docs.python.org/reference/datamodel.html
  • Kevin
    Kevin about 12 years
    I think there's a mistake in your update, SomeCallable() should read SomeCallable (I'm not sure enough to fix it myself, I'll remove the comment if necessary)
  • orip
    orip about 12 years
    @Kevin - I believe the update is fine (and runs). It's instances of SomeCallable that are callable. I'll change the class name :)
  • Lucky
    Lucky over 6 years
    would you explain why did you inherit from object ? and how notify_bar method knows which observer function/method is it calling ?
  • orip
    orip over 6 years
    @Lucky inheriting from object is an ancient python2 quirk, ensuring we get new-style classes instead of old-style classes. Unnecessary in python3. notify_bar doesn't know or care which callable it's calling. It appended them to the list earlier, and now it's calling them. They're opaque as far as it's concerned.