GUI Frames and classmethod

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Zak Arntson

    GUI Frames and classmethod

    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(Fra me):
    def __init__(self, owner, pos, size=None):
    Frame.__init__( self, owner, pos, size)
    ism = self.input_stat e_machine

    ism.add_rule("N one", "LWait", (MOUSEBUTTONDOW N, 1))
    ##
    ism.add_rule("L Wait", "None", (MOUSEBUTTONDOW N, 2))
    ism.add_rule("L Wait", "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.ent er_state_LWait( ) or
    ButtonFrame.lea ve_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_me thod(self):
    pass
    _empty_state_me thod = classmethod(_em pty_state_metho d)

    def create_empty_st ate_methods(sel f):
    ism = self.input_stat e_machine
    for timing in ('enter','durin g','leave'):
    for state in ism.states:
    method = '%s_state_%s' % (timing, state)
    if not hasattr(self.__ class__, method):
    setattr(self.__ class__, method, Frame._empty_st ate_method)
    ###

    This means that if the user hasn't implemented
    ButtonFrame.dur ing_state_LWait (), for example, an empty function will
    be provided (pointing to _empty_state_me thod().

    (Aside: I'm considering putting all these state methods in a
    dictionary of dictionaries so you can do a quick
    myButtonFrame.s tate_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_em pty_state_metho ds(). So my ButtonFrame class looks
    like:

    ###
    class ButtonFrame(Fra me):
    def __init__(self, owner, pos, size=None):
    Frame.__init__( self, owner, pos, size)
    ism = self.input_stat e_machine

    ism.add_rule("N one", "LWait", (MOUSEBUTTONDOW N, 1))
    ##
    ism.add_rule("L Wait", "None", (MOUSEBUTTONDOW N, 2))
    ism.add_rule("L Wait", "None", (MOUSEBUTTONUP, 1))

    self.create_emp ty_state_method s()
    ###

    Note the last line. When programming EVERY child I have to remember to
    add this self.create_emp ty_state_method s() 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_emp ty_state_method s()
    ###

    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(B uttonFrame().in it()))
    ###
    class Frame:
    def __init__(self, owner, pos, size=None):
    self.owner = owner
    self.children = []
    # more setup code here.

    def init(self):
    self.create_emp ty_state_method s()
    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
  • Scott David Daniels

    #2
    Re: GUI Frames and classmethod

    Zak Arntson wrote:[color=blue]
    > Note the last line. When programming EVERY child I have to remember to
    > add this self.create_emp ty_state_method s() 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.[/color]

    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_stat e_machine = ...
    # more pre-setup
    self.addrules()
    self.create_emp ty_states()
    # more post-setup

    def addrules():
    pass

    Button (for example) looks like:

    class ButtonFrame(Bas eFrame):
    def addrules():
    ism = self.input_stat e_machine
    ism.add_rule("N one", "LWait", (MOUSEBUTTONDOW N, 1))
    ism.add_rule("L Wait", "None", (MOUSEBUTTONDOW N, 2))
    ism.add_rule("L Wait", "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(BaseF rame):
    def __init__(self, ...):
    # more pre-setup
    super(FunkFrame , self).__init__( self, ...)
    # more post-setup

    def addrules():
    self.input_stat e_machine.add_r ule(
    "None", "RWait", (MOUSEBUTTONDOW N, 1))
    [color=blue]
    > 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[/color]

    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(se lf, newstate):
    try:
    action = self.transition s[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(Val ueError):
    def __str__(self):
    return 'No transition defined for %r -> %r' % self.args


    --Scott David Daniels
    Scott.Daniels@A cm.Org

    Comment

    • Zak Arntson

      #3
      Re: GUI Frames and classmethod

      On Fri, 03 Dec 2004 14:48:30 -0800, Scott David Daniels
      <scott.daniels@ acm.org> wrote:[color=blue]
      > Zak Arntson wrote:[color=green]
      > > 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[/color]
      >
      > 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:[/color]

      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.

      --
      Zak Arntson
      http://www.harlekin-maus.com - Games - Lots of 'em

      Comment

      • Scott David Daniels

        #4
        Re: GUI Frames and classmethod

        Zak Arntson wrote:[color=blue]
        > On Fri, 03 Dec 2004 14:48:30 -0800, Scott David Daniels
        > <> wrote:
        > .... 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.[/color]
        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
        Scott.Daniels@a cm.org

        Comment

        • Zak Arntson

          #5
          Re: GUI Frames and classmethod

          On Mon, 06 Dec 2004 13:08:15 -0800, Scott David Daniels
          <scott.daniels@ acm.org> wrote:[color=blue]
          > Zak Arntson wrote:[color=green]
          > > On Fri, 03 Dec 2004 14:48:30 -0800, Scott David Daniels[/color]
          > 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
          > Scott.Daniels@a cm.org[/color]

          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_Non e,
          ("None", "During"): during_state_No ne,
          ("None", "Leave"): leave_state_Non e,
          ("LWait", "Enter"): enter_state_LWa it,
          ("LWait", "During"): during_state_LW ait,
          ("LWait", "Leave"): leave_state_LWa it}

          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_Non e, "During": during_state_No ne,
          "Leave": leave_state_Non e},
          "LWait": {"Enter": enter_state_LWa it, "During": during_state_Lw ait,
          "Leave": leave_state_LWa it}}


          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.

          --
          Zak Arntson
          http://www.harlekin-maus.com - Games - Lots of 'em

          Comment

          • Scott David Daniels

            #6
            Re: GUI Frames and classmethod

            Zak Arntson wrote:[color=blue]
            > On Mon, 06 Dec 2004 13:08:15 -0800, Scott David Daniels
            > <scott.daniels@ acm.org> wrote:
            >[color=green]
            >>Zak Arntson wrote:
            >>[color=darkred]
            >>>On Fri, 03 Dec 2004 14:48:30 -0800, Scott David Daniels wrote:[/color]
            >>...The real advantage is clarity: the inner dictionaries in a dict-of-dict
            >>implementatio n 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.[/color]
            >
            > ... If I see:
            > {("None", "Enter"): enter_state_Non e,
            > ("None", "During"): during_state_No ne,
            > ("None", "Leave"): leave_state_Non e,
            > ("LWait", "Enter"): enter_state_LWa it,
            > ("LWait", "During"): during_state_LW ait,
            > ("LWait", "Leave"): leave_state_LWa it}
            >
            > 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_Non e, "During": during_state_No ne,
            > "Leave": leave_state_Non e},
            > "LWait": {"Enter": enter_state_LWa it, "During": during_state_Lw ait,
            > "Leave": leave_state_LWa it}}
            >[/color]
            First, I'd probably write the above as some variation of the following:
            {"None": {"Enter": enter_state_Non e,
            "During": during_state_No ne,
            "Leave": leave_state_Non e},
            "LWait": {"Enter": enter_state_LWa it,
            "During": during_state_Lw ait,
            "Leave": leave_state_LWa it}
            }
            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_non e, 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((stat e, 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.durin g = whenever
            NullState.leave = forever


            --Scott David Daniels
            Scott.Daniels@a cm.org

            Comment

            • Jeremy Bowers

              #7
              Re: GUI Frames and classmethod

              On Mon, 06 Dec 2004 14:11:04 -0800, Scott David Daniels wrote:[color=blue]
              > 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.[/color]

              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.

              Comment

              Working...