class Menu: def __init__(self, start=None): # inherited constructor self.menu = start or self.empty # passed-in or default def __getitem__(self, index): # on 'menu[index]', 'in' return self.menu[index] # index a wrapped menu def __setitem__(self, index, value): # on 'menu[index] = value' self.menu[index] = value # set a menu's key/index def __getattr__(self, name): # on 'menu.other' return getattr(self.menu, name) # keys, append, sort... def run(self, prompt='?'): # a 'real' method try: while 1: # common interactive loop print '\n\tMENU...' self.showOptions() command = raw_input(prompt) try: flag = self.runCommand(command) except (IndexError, KeyError): print "what: '%s'?" % command else: if flag: break except EOFError: pass # ctrl-d still exits all class DictMenu(Menu): empty = {} # or extend __init__ def __add__(self, other): # on 'dictmenu + other' new = DictMenu() # make a new instance for key in self.keys(): new[key] = self[key] # copy 'self' dict for key in other.keys(): new[key] = other[key] # add other dict return new __radd__ = __add__ # transitive for mappings def extend(self, other): # change menu in-place for key in other.keys(): self[key] = other[key] # uses __setitem__ def showOptions(self): # more 'real' methods options = self.keys() # uses __getattr__ options.sort() for cmd in options: print '\t\t' + cmd def runCommand(self, cmd): return self[cmd]() # uses __getitem__ class ListMenu(Menu): empty = [] # def __add__(self, other): # on 'listmenu + other' # return ListMenu(self.menu + other) # make a new instance def __add__(self, other): # on 'listmenu + other' new = self.menu[:] # copy my list for x in other: # loop over other: a menu too? new.append(x) # like DictMenu.__add__ return ListMenu(new) # make a new instance def __radd__(self, other): # on 'non-listmenu + listmenu' return ListMenu(other + self.menu) def extend(self, other): # change menu in-place self.append(other) # uses __getattr__ def showOptions(self): i = 0 # 'in' uses __getitem__ for name, func in self: print '\t\t%d) %s' % (i, name); i=i+1 def runCommand(self, cmd): try: index = eval(cmd) # convert string to number except: raise IndexError return self[index][1]() # uses __getitem__