Python: Callbacks, Delegates, ... ? What is common?
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.
Related videos on Youtube
okoman
Updated on April 06, 2020Comments
-
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 about 13 yearsnice example, but what about the 'call' you mention, does it allow to register
foo.add_bar_observer(callable)
? -
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 about 12 yearsI think there's a mistake in your update,
SomeCallable()
should readSomeCallable
(I'm not sure enough to fix it myself, I'll remove the comment if necessary) -
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 over 6 yearswould you explain why did you inherit from object ? and how notify_bar method knows which observer function/method is it calling ?
-
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.