I'm currently implementing a game GUI, where there are three components to the screen: A battle, a command button area and a city view area. Each of these are rectangular, and handle interactions in different ways.
For example, on the battle "frame" you can select units, right-click to deliver context-sensitive commands, etc. On the command frame, you select buttons to deliver commands, change the state of the battle frame (i.e., a move command sets the battle frame to accept a move-to location). This sort of thing. So I'm implementing the frame code right now. Each Frame object has a StateMachine object. Which mean that in the __init__ code of a child of Frame, you add rules to the StateMachine object: ### class ButtonFrame(Frame): def __init__(self, owner, pos, size=None): Frame.__init__(self, owner, pos, size) ism = self.input_state_machine ism.add_rule("None", "LWait", (MOUSEBUTTONDOWN, 1)) ## ism.add_rule("LWait", "None", (MOUSEBUTTONDOWN, 2)) ism.add_rule("LWait", "None", (MOUSEBUTTONUP, 1)) ### This is all fine and good. Now, when creating a Frame child class, you make an implicit agreement that you'll create methods for each state, such as ButtonFrame.enter_state_LWait() or ButtonFrame.leave_state_None(). My current approach is that in the Frame class, I have a method to call _after_ initialization that creates a bunch of dummy methods so the user doesn't have to implement EVERY state change method in a Frame child: ### ## @classmethod -- Python 2.4 def _empty_state_method(self): pass _empty_state_method = classmethod(_empty_state_method) def create_empty_state_methods(self): ism = self.input_state_machine for timing in ('enter','during','leave'): for state in ism.states: method = '%s_state_%s' % (timing, state) if not hasattr(self.__class__, method): setattr(self.__class__, method, Frame._empty_state_method) ### This means that if the user hasn't implemented ButtonFrame.during_state_LWait(), for example, an empty function will be provided (pointing to _empty_state_method(). (Aside: I'm considering putting all these state methods in a dictionary of dictionaries so you can do a quick myButtonFrame.state_dict['during']['LWait'] to access the proper method) What this now means is that when implementing a child, I am not only forcing a call to Frame.__init__(), but also Frame.create_empty_state_methods(). So my ButtonFrame class looks like: ### class ButtonFrame(Frame): def __init__(self, owner, pos, size=None): Frame.__init__(self, owner, pos, size) ism = self.input_state_machine ism.add_rule("None", "LWait", (MOUSEBUTTONDOWN, 1)) ## ism.add_rule("LWait", "None", (MOUSEBUTTONDOWN, 2)) ism.add_rule("LWait", "None", (MOUSEBUTTONUP, 1)) self.create_empty_state_methods() ### Note the last line. When programming EVERY child I have to remember to add this self.create_empty_state_methods() line. My question: What are Pythonic alternatives to this sort of thing? I can think of a few solutions, but none of them seem to be obviously advantageous: 1. All children don't call __init__, but have an _init() method that is called by Frame.__init__(). That way ButtonFrame has an _init() method rather than an __init__() method. This may be my best option. ### class Frame: def __init__(self, owner, pos, size=None): self.owner = owner self.children = [] # more setup code here. self._init() self.create_empty_state_methods() ### 2. Frame has an init() function that needs to be called following the instantiation of a Frame (or Frame child object). I'm not too keen on this, because it requires creating the Frame object and _then_ running an init() method. I try to keep that sort of thing to a minimum because it makes quick object creation a little funky. (init() has to return self so you can do a myList.append(ButtonFrame().init())) ### class Frame: def __init__(self, owner, pos, size=None): self.owner = owner self.children = [] # more setup code here. def init(self): self.create_empty_state_methods() return self b = Frame() b.init() myList.append(b) ### Phew! Hope that's not overly long! Now I can't be the first person to want a pre- and post- child init code! I'm worried that I'm overlooking something or there's an even more Pythonic way to do things than above. -- Zak Arntson http://www.harlekin-maus.com - Games - Lots of 'em -- http://mail.python.org/mailman/listinfo/python-list