GUI Frames and classmethod

Z

Zak Arntson

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.
 
S

Scott David Daniels

Zak said:
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?
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.

To your explicit question: The trick is to name the middle part, and
override it you want. Then your base class can invoke the appropriate
building at the point it likes.

Base frame looks like:

class BaseFrame(...):
def __init__(self, ....):
self.input_state_machine = ...
# more pre-setup
self.addrules()
self.create_empty_states()
# more post-setup

def addrules():
pass

Button (for example) looks like:

class ButtonFrame(BaseFrame):
def addrules():
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))

See, you needn't even muck with __init__ here, if all you want is
some rules added. Something which actually wants to do some init stuff:

class FunkFrame(BaseFrame):
def __init__(self, ...):
# more pre-setup
super(FunkFrame, self).__init__(self, ...)
# more post-setup

def addrules():
self.input_state_machine.add_rule(
"None", "RWait", (MOUSEBUTTONDOWN, 1))
> 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

Really, I think the above is a bad idea. Don't implement empty
methods. Make a dictionary of state transitions, and store code in it.
Note: you don't need a dictionary of dictionaries; you could use a
dictionary of pairs. Do something on each attempted transition like the
following:

def change_state(self, newstate):
try:
action = self.transitions[self.current, newstate]
except KeyError:
raise NoRuleError, (self.current, newstate)
# or pass to ignore missing transitions.
else:
action(self)

This method belongs in BaseFrame and assumes a class like:

class NoRuleError(ValueError):
def __str__(self):
return 'No transition defined for %r -> %r' % self.args


--Scott David Daniels
(e-mail address removed)
 
Z

Zak Arntson

Really, I think the above is a bad idea. Don't implement empty
methods. Make a dictionary of state transitions, and store code in it.
Note: you don't need a dictionary of dictionaries; you could use a
dictionary of pairs. Do something on each attempted transition like the
following:

A dictionary of methods! Thanks. Boy, do I feel silly now. So I have a
more general question: A dictionary of dictionaries is slower than a
dictionary of tuples, right? Because when Python accesses a
dictionary, it produces a hash from the key and finds that in its hash
table. Producing a hash from a tuple is much faster than producting
two hashes and doing two lookups. At least that's what I'm assuming.
 
S

Scott David Daniels

Zak said:
.... question: A dictionary of dictionaries is slower than a
dictionary of tuples, right? Because when Python accesses a
dictionary, it produces a hash from the key and finds that in its hash
table. Producing a hash from a tuple is much faster than producting
two hashes and doing two lookups. At least that's what I'm assuming.
Most likely so. Possibly an equal amount of has work -- hash of a pair
is a function of hashes of the lelements, but fewer trips in and out of
the interpretter. So, one less lookup, less refcount fiddling, and
fewer dispatches through the interpretter.

The real advantage is clarity: the inner dictionaries in a dict-of-dict
implementation have no real "meaning." The extra overhead (in the mind
of the program reader) involved in creating inner dictionaries at
appropriate times makes the code harder to understand.

--Scott David Daniels
(e-mail address removed)
 
Z

Zak Arntson

Most likely so. Possibly an equal amount of has work -- hash of a pair
is a function of hashes of the lelements, but fewer trips in and out of
the interpretter. So, one less lookup, less refcount fiddling, and
fewer dispatches through the interpretter.

The real advantage is clarity: the inner dictionaries in a dict-of-dict
implementation have no real "meaning." The extra overhead (in the mind
of the program reader) involved in creating inner dictionaries at
appropriate times makes the code harder to understand.

--Scott David Daniels
(e-mail address removed)

I feel differently (though I'd accept being in the minority on this
one). If you have a dictionary of tuples where the first member is an
often-repeated value, then it makes more sense (again, to me) to split
it up.

So if I see:
{("None", "Enter"): enter_state_None,
("None", "During"): during_state_None,
("None", "Leave"): leave_state_None,
("LWait", "Enter"): enter_state_LWait,
("LWait", "During"): during_state_LWait,
("LWait", "Leave"): leave_state_LWait}

I want to split it up. This is more intuitive for me because it shows
an obvious one-many relationship between the outer keys and the inner
keys.
{"None": {"Enter": enter_state_None, "During": during_state_None,
"Leave": leave_state_None},
"LWait": {"Enter": enter_state_LWait, "During": during_state_Lwait,
"Leave": leave_state_LWait}}


I have to confess to not knowing whether one way is more "Pythonic"
than the other. The first method is mostly easier to code with, but
doesn't explicitly state a one-many relationship. The second give
lengthier code for most operations.
 
S

Scott David Daniels

Zak said:
... If I see:
{("None", "Enter"): enter_state_None,
("None", "During"): during_state_None,
("None", "Leave"): leave_state_None,
("LWait", "Enter"): enter_state_LWait,
("LWait", "During"): during_state_LWait,
("LWait", "Leave"): leave_state_LWait}

I want to split it up. This is more intuitive for me because it shows
an obvious one-many relationship between the outer keys and the inner
keys.
{"None": {"Enter": enter_state_None, "During": during_state_None,
"Leave": leave_state_None},
"LWait": {"Enter": enter_state_LWait, "During": during_state_Lwait,
"Leave": leave_state_LWait}}
First, I'd probably write the above as some variation of the following:
{"None": {"Enter": enter_state_None,
"During": during_state_None,
"Leave": leave_state_None},
"LWait": {"Enter": enter_state_LWait,
"During": during_state_Lwait,
"Leave": leave_state_LWait}
}
to show the two-layer structure. I'd also prefer function names
describing what is done, rather than why the code was called, but
the names may only be in the current form because we are talking
about coding, and have no real application here.

Second, I was referring to code like:

try:
inner = table[state]
except KeyError:
table[state] = inner = {}
inner[action] = whatever

vs. code like this:

table[state, action] = whatever

That is, dynamic table modification code for a table of pairs is
clearer. If you are simply creating the table from a simple source,
I might make a different choice. I am not particularly big on
names like enter_state_none, nor one of prescribing a structure
that makes the creation of lots of no-ops necessary. I'd rather
see code using the system look like:

try:
action = table[state, stimulus]
except KeyError:
pass
else:
action(arglist)

or even:

def noop(*args, **kwargs):
pass
...
table.get((state, stimulus), noop)(arglist)


If each state is an instance with a dictionary, you might even want
to go with:
class State(object): pass # or whatever
...
NullState = State()
NullState.enter = whatever
NullState.during = whenever
NullState.leave = forever


--Scott David Daniels
(e-mail address removed)
 
J

Jeremy Bowers

Second, I was referring to code like:

try:
inner = table[state]
except KeyError:
table[state] = inner = {}
inner[action] = whatever

vs. code like this:

table[state, action] = whatever

That is, dynamic table modification code for a table of pairs is clearer.

But it isn't quite as tradeoff free as you say; you do lose the ability to
say table[state] and get just the information relevant to your state (you
might take the .keys() of that or something).

In this case, it may not be a big deal; depends on what the program does
and how the programmer thinks. In other cases, dicts of dicts can make
perfect sense. For instance, I have a Registry type that uses
dicts-in-dicts the obvious way to store things like
"table1.table2.table3.value", and that way there is a coherent way to pass
"table1.table2.table3" around. Yeah, you could work out a string or tuple
subclass that could still work, but that's a lot more work :) and you'd
still have a hard time getting all keys from a table without searching the
whole thing.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,167
Latest member
SusanaSwan
Top