Chain of Responsibility in Python

There are many examples of the implementation of the Chain of Responsibility design pattern in Python out there, some adding some new bits, some bearing some baggage and a few wishful ones. However, I recently found myself in need of a simpler and adaptable example.

Below is the python version of the C++ example code given in the book Design Patterns: Elements of Reusable Object-Oriented Software. I hope you find it useful in your own projects.

The important part is the HelpHandler class, which manages the successors in the chain

class HelpHandler (object):
  def __init__(self, successor=0, topic=NO_HELP_TOPIC):
    self._successor = successor
        self._topic = topic
    def HasHelp(self):
        return self._topic != NO_HELP_TOPIC;
    def HandleHelp(self):
        if self._successor != 0:
            self._successor.HandleHelp()
    def SetHandler(self,h,t):
        self._successor = h
        self._h = t

In our case we have a Widget class that inherits from HelpHandler:

class Widget(HelpHandler):
    def __init__(self, w, t):
        super(Widget,self).__init__(w,t)

Which we will use to build two sub-classes (Dialog and Button)

class Button(Widget):
    def __init__(self, d, t):
        super(Button,self).__init__(d,t)
    def HandleHelp(self):
        if self.HasHelp():
            print "Button Help"
        else:
            return super(Button, self).HandleHelp()
 
class Dialog(Widget):
    def __init__(self, h, t):
        super(Dialog,self).__init__(h,t)
        self.SetHandler(h,t)
    def HandleHelp(self):
        if self.HasHelp():
            print "Dialog Help"
        else:
            return super(Dialog, self).HandleHelp()

In the root of our chain we will have an Application Class that will handle the request for help:

class Application(HelpHandler):
    def __init__(self, t):
        super(Application,self).__init__(0,t)
    def HandleHelp(self):
        print "Application Help"

Creating a chain is as easy as creating an Application, Dialog, and Button and invoking the help anywhere in the chain. Like so:

PRINT_TOPIC = 1
PAPER_ORIENTATION = 2
APPLICATION_TOPIC = 3
NO_HELP_TOPIC = -1

application = Application(APPLICATION_TOPIC)
dialog = Dialog(application, PRINT_TOPIC)
button = Button(dialog, NO_HELP_TOPIC)

# invoking help in the chain
button.HandleHelp()

For your full enjoyment here is the complete implementation: