call function of class instance with no assigned name?

Discussion in 'Python' started by George Oliver, May 5, 2009.

  1. hi, I'm a Python beginner with a basic question. I'm writing a game
    where I have keyboard input handling defined in one class, and command
    execution defined in another class. The keyboard handler class
    contains a dictionary that maps a key to a command string (like 'h':
    'left') and the command handler class contains functions that do the
    commands (like def do_right(self):),

    I create instances of these classes in a list attached to a third,
    'brain' class. What I'd like to have happen is when the player presses
    a key, the command string is passed to the command handler, which runs
    the function. However I can't figure out a good way to make this
    happen.

    I've tried a dictionary mapping command strings to functions in the
    command handler class, but those dictionary values are evaluated just
    once when the class is instantiated. I can create a dictionary in a
    separate function in the command handler (like a do_command function)
    but creating what could be a big dictionary for each input seems kind
    of silly (unless I'm misunderstanding something there).

    What would be a good way to make this happen, or is there a different
    kind of architecture I should be thinking of?
     
    George Oliver, May 5, 2009
    #1
    1. Advertising

  2. George Oliver

    Chris Rebert Guest

    On Tue, May 5, 2009 at 8:52 AM, George Oliver <> wrote:
    > hi, I'm a Python beginner with a basic question. I'm writing a game
    > where I have keyboard input handling defined in one class, and command
    > execution defined in another class. The keyboard handler class
    > contains a dictionary that maps a key to a command string (like 'h':
    > 'left') and the command handler class contains functions that do the
    > commands (like def do_right(self):),
    >
    > I create instances of these classes in a list attached to a third,
    > 'brain' class. What I'd like to have happen is when the player presses
    > a key, the command string is passed to the command handler, which runs
    > the function. However I can't figure out a good way to make this
    > happen.
    >
    > I've tried a dictionary mapping command strings to functions in the
    > command handler class, but those dictionary values are evaluated just
    > once when the class is instantiated. I can create a dictionary in a
    > separate function in the command handler (like a do_command function)
    > but creating what could be a big dictionary for each input seems kind
    > of silly (unless I'm misunderstanding something there).
    >
    > What would be a good way to make this happen, or is there a different
    > kind of architecture I should be thinking of?


    You could exploit Python's dynamism by using the getattr() function:

    key2cmd = {'h':'left'}
    cmd_name = key2cmd[keystroke]
    getattr("do_"+cmd_name, cmd_handler)() #same as cmd_handler.do_left()


    Cheers,
    Chris
    --
    http://blog.rebertia.com
     
    Chris Rebert, May 5, 2009
    #2
    1. Advertising

  3. Chris Rebert <> writes:

    > On Tue, May 5, 2009 at 8:52 AM, George Oliver <> wrote:
    >> hi, I'm a Python beginner with a basic question. I'm writing a game
    >> where I have keyboard input handling defined in one class, and
    >> command execution defined in another class. The keyboard handler
    >> class contains a dictionary that maps a key to a command string (like
    >> 'h': 'left') and the command handler class contains functions that do
    >> the commands (like def do_right(self):),
    >>
    >> I create instances of these classes in a list attached to a third,
    >> 'brain' class. What I'd like to have happen is when the player
    >> presses a key, the command string is passed to the command handler,
    >> which runs the function. However I can't figure out a good way to
    >> make this happen.
    >>
    >> I've tried a dictionary mapping command strings to functions in the
    >> command handler class, but those dictionary values are evaluated just
    >> once when the class is instantiated. I can create a dictionary in a
    >> separate function in the command handler (like a do_command function)
    >> but creating what could be a big dictionary for each input seems kind
    >> of silly (unless I'm misunderstanding something there).
    >>
    >> What would be a good way to make this happen, or is there a different
    >> kind of architecture I should be thinking of?

    >
    > You could exploit Python's dynamism by using the getattr() function:
    >
    > key2cmd = {'h':'left'}
    > cmd_name = key2cmd[keystroke]
    > getattr("do_"+cmd_name, cmd_handler)() #same as cmd_handler.do_left()


    getattr(cmd_handler, "do_" + cmd_name)() will work even better!

    --
    Arnaud
     
    Arnaud Delobelle, May 5, 2009
    #3
  4. On May 5, 9:01 am, Chris Rebert <> wrote:
    > On Tue, May 5, 2009 at 8:52 AM, George Oliver <> wrote:


    > > I create instances of these classes in a list attached to a third,
    > > 'brain' class.

    >
    > You could exploit Python's dynamism by using the getattr() function:



    Thanks for the responses -- I should have mentioned that I looked at
    the getattr() function, but as I instantiate the key handler and
    command handler classes in a list (like handlers = [command_handler(),
    keyboard_handler()], I'm unsure how to reference that class instance
    in the getattr in a straightforward way (short of keeping track of
    each instance's position in the handlers list). Is there a typical way
    of doing that?
     
    George Oliver, May 5, 2009
    #4
  5. George Oliver

    Dave Angel Guest

    George Oliver wrote:
    > hi, I'm a Python beginner with a basic question. I'm writing a game
    > where I have keyboard input handling defined in one class, and command
    > execution defined in another class. The keyboard handler class
    > contains a dictionary that maps a key to a command string (like 'h':
    > 'left') and the command handler class contains functions that do the
    > commands (like def do_right(self):),
    >
    > I create instances of these classes in a list attached to a third,
    > 'brain' class. What I'd like to have happen is when the player presses
    > a key, the command string is passed to the command handler, which runs
    > the function. However I can't figure out a good way to make this
    > happen.
    >
    > I've tried a dictionary mapping command strings to functions in the
    > command handler class, but those dictionary values are evaluated just
    > once when the class is instantiated. I can create a dictionary in a
    > separate function in the command handler (like a do_command function)
    > but creating what could be a big dictionary for each input seems kind
    > of silly (unless I'm misunderstanding something there).
    >
    > What would be a good way to make this happen, or is there a different
    > kind of architecture I should be thinking of?
    >
    >

    You have lots of words, but no code, and no explanation of why you're
    choosing this "architecture." So it's unclear just what to propose to
    you, without sticking to generalities.

    1) forget about getattr() unless you have hundreds of methods in your
    map. The real question is why you need two maps. What good is the
    "command string" doing you? Why not just map the keyvalues directly
    into function objects?

    2) Look at the following simple example, where I'm assuming that a
    "keycode" is simply an ASCII character.

    class Command(object):
    def __init__(self):
    pass
    def doEnter(self):
    print "Enter is done"
    def doA(self):
    print "A is done"

    cmd = Command()



    table = {
    13: cmd.doEnter,
    65: cmd.doA
    }

    print "trying 13"
    key = 13
    table[key]()
    print "trying 65"
    key = 65
    table[key]()

    3) As for rebuilding the dictionary, that just depends on where you
    build it, and what it's lifetime is. If it's got enough lifetime, and
    appropriate scope, you wouldn't have to rebuild anything.

    4) Code up a first try, and when you get stuck, ask a specific question.

    You said you're a beginner. So keep it as simple as possible.l
     
    Dave Angel, May 5, 2009
    #5
  6. On May 5, 11:59 am, Dave Angel <> wrote:

    > 1) forget about getattr() unless you have hundreds of methods in your
    > map. The real question is why you need two maps. What good is the
    > "command string" doing you? Why not just map the keyvalues directly
    > into function objects?



    Thanks for the reply Dave. I understand your example and it's what I
    originally used. Here is more detail on what I'm doing now, I hope
    this will explain my question better.

    In the game I'm writing the player, monsters, items and so on are
    instances of class Thing, like:

    class Thing(object):
    def __init__(self, x, y, name):
    self.x, self.y = x, y
    self.name = name
    self.brain = None

    Some Things have an instance of class Brain attached. The Brain
    instance has a list of handlers, like:

    class Brain(object):
    def __init__(self):
    self.handlers = []

    A handler class defines some functionality for the Brain. Each Brain
    has an update method like this:

    def update(self, arguments):
    for handler in self.handlers:
    handler.update(arguments)

    So on each pass through the main game loop, it calls the update method
    of all the brains in the game, which run their handler update methods
    to change the state of the game.

    A handler would be something like a key input handler. The key input
    handler is defined separately from the command handler in the case I
    want to use a different method of input, for example a mouse or
    joystick.

    In the dictionary of key inputs I could map each input directly to a
    function. However there is no instance name I can call the function
    on, as I create a thing, add a brain, and add handlers to the brain
    like this:

    player = Thing(26, 16, 'player')
    player.brain = Brain()
    player.brain.add_handlers(
    commandHandler(player.brain, player),
    keyboardHandler(player.brain),
    fovHandler(player.brain))


    So what I'm wondering is how to reference the instance in each brain's
    list of handlers when I want to map something like a key input to a
    command, or what a better way might be to structure the code.
     
    George Oliver, May 5, 2009
    #6
  7. George Oliver

    Aaron Brady Guest

    On May 5, 2:17 pm, George Oliver <> wrote:
    > On May 5, 11:59 am, Dave Angel <> wrote:
    >
    > > 1) forget about getattr() unless you have hundreds of methods in your
    > > map.  The real question is why you need two maps. What good is the
    > > "command string" doing you?   Why not just map the keyvalues directly
    > > into function objects?

    >
    > Thanks for the reply Dave. I understand your example and it's what I
    > originally used. Here is more detail on what I'm doing now, I hope
    > this will explain my question better.
    >
    > In the game I'm writing the player, monsters, items and so on are
    > instances of class Thing, like:
    >
    > class Thing(object):
    >     def __init__(self, x, y, name):
    >         self.x, self.y = x, y
    >         self.name = name
    >         self.brain = None
    >
    > Some Things have an instance of class Brain attached. The Brain
    > instance has a list of handlers, like:
    >
    > class Brain(object):
    >     def __init__(self):
    >         self.handlers = []
    >
    > A handler class defines some functionality for the Brain. Each Brain
    > has an update method like this:
    >
    > def update(self, arguments):
    >     for handler in self.handlers:
    >         handler.update(arguments)
    >
    > So on each pass through the main game loop, it calls the update method
    > of all the brains in the game, which run their handler update methods
    > to change the state of the game.
    >
    > A handler would be something like a key input handler. The key input
    > handler is defined separately from the command handler in the case I
    > want to use a different method of input, for example a mouse or
    > joystick.
    >
    > In the dictionary of key inputs I could map each input directly to a
    > function. However there is no instance name I can call the function
    > on, as I create a thing, add a brain, and add handlers to the brain
    > like this:
    >
    > player = Thing(26, 16, 'player')
    > player.brain = Brain()
    > player.brain.add_handlers(
    >                             commandHandler(player.brain, player),
    >                             keyboardHandler(player.brain),
    >                             fovHandler(player..brain))
    >
    > So what I'm wondering is how to reference the instance in each brain's
    > list of handlers when I want to map something like a key input to a
    > command, or what a better way might be to structure the code.


    I'm not entirely sure I follow, but you may want to try keeping a set
    (or list) of handlers that you pass in to the 'add_handlers' function,
    and trying the 'getattr( handlerX, keyY )' on each of them, possible
    only until you have a success. You could also cache these results to
    avoid performing the same search subsequently.

    Otherwise, query each of the passed-in handlers when they are passed
    in for a list of events they can handle; this may be by a brute
    'getattr( x ) for x in ALL_EVENTS', or by maintaining a list of
    handlers on a per-object basis, and merely combining the dictionaries;
    then pick one or all of the handlers you've accumulated for an event
    when the event occurs.

    </run-on sentence>

    If you're really trying to be clever, you might use a metaclass or
    class decorator to accumulate what events are handled in a class; or
    just try the '__dict__' member of the /class/.

    Will any of your handlers be handling overlapping or duplicate
    events? Do they all get a crack at it, or do you follow a pre-
    deterimend order of precedence, or follow the order in which they were
    passed in?

    I'd probably try to discourage you from circularly linking the object
    and handlers, not only for practical reasons.

    There is also the possibility you could use dynamic mix-ins to create
    a specialized once-in-a-lifetime brain class:

    def create_brain( handlers ):
    class new_brain( Brain ):
    pass
    for x in handlers:
    setattr( new_brain, x.__name__, x )
    return new_brain

    brain= create_brain( handlers )( creation_args )

    Forgive, just Thing-king aloud.
     
    Aaron Brady, May 5, 2009
    #7
  8. Thanks for the suggestions so far. I've taken the advice to keep
    things simple so currently I'm just creating one instance of the
    commandHandler and assigning it a name with command = commandHandler
    (). This makes it easy to call it from any of the other handlers, and
    I think this will work for what I want the game to do.
     
    George Oliver, May 5, 2009
    #8
  9. George Oliver

    Rhodri James Guest

    On Tue, 05 May 2009 16:52:39 +0100, George Oliver
    <> wrote:

    > hi, I'm a Python beginner with a basic question. I'm writing a game
    > where I have keyboard input handling defined in one class, and command
    > execution defined in another class. The keyboard handler class
    > contains a dictionary that maps a key to a command string (like 'h':
    > 'left') and the command handler class contains functions that do the
    > commands (like def do_right(self):),
    >
    > I create instances of these classes in a list attached to a third,
    > 'brain' class. What I'd like to have happen is when the player presses
    > a key, the command string is passed to the command handler, which runs
    > the function. However I can't figure out a good way to make this
    > happen.
    >
    > I've tried a dictionary mapping command strings to functions in the
    > command handler class, but those dictionary values are evaluated just
    > once when the class is instantiated. I can create a dictionary in a
    > separate function in the command handler (like a do_command function)
    > but creating what could be a big dictionary for each input seems kind
    > of silly (unless I'm misunderstanding something there).


    Taking a wild guess when you were creating that dictionary mapping
    command strings to functions, did you map to function calls or to the
    function objects themselves? I'd make a small wager you did the former,
    and the latter would have done what you want. Something like this,
    maybe?

    >>>> CODE FOLLOWS<<<<


    class DoSomething(object):
    def do_this(self):
    print "Doing this"

    def do_that(self):
    print "Doing that"

    def do_the_other(self):
    print "Doing the other"

    _CMD_DICT = { 'this' : do_this,
    'that' : do_that,
    'the other' : do_the_other }

    def update(self, cmd):
    try:
    DoSomething._CMD_DICT[cmd](self)
    except KeyError:
    print "Foul! Foul, I say!"

    >>>> END CODE<<<<


    To be honest, the getattr approach is probably as easy to follow
    and less prone to forgetting to update the dictionary.


    --
    Rhodri James *-* Wildebeeste Herder to the Masses
     
    Rhodri James, May 6, 2009
    #9
  10. George Oliver

    Dave Angel Guest

    George Oliver wrote:
    > On May 5, 11:59 am, Dave Angel <> wrote:
    >
    >
    >> 1) forget about getattr() unless you have hundreds of methods in your
    >> map. The real question is why you need two maps. What good is the
    >> "command string" doing you? Why not just map the keyvalues directly
    >> into function objects?
    >>

    >
    >
    > Thanks for the reply Dave. I understand your example and it's what I
    > originally used. Here is more detail on what I'm doing now, I hope
    > this will explain my question better.
    >
    > In the game I'm writing the player, monsters, items and so on are
    > instances of class Thing, like:
    >
    > class Thing(object):
    > def __init__(self, x, y, name):
    > self.x, self.y = x, y
    > self.name = name
    > self.brain = None
    >
    > Some Things have an instance of class Brain attached. The Brain
    > instance has a list of handlers, like:
    >
    > class Brain(object):
    > def __init__(self):
    > self.handlers = []
    >
    > A handler class defines some functionality for the Brain. Each Brain
    > has an update method like this:
    >
    > def update(self, arguments):
    > for handler in self.handlers:
    > handler.update(arguments)
    >
    > So on each pass through the main game loop, it calls the update method
    > of all the brains in the game, which run their handler update methods
    > to change the state of the game.
    >
    > A handler would be something like a key input handler. The key input
    > handler is defined separately from the command handler in the case I
    > want to use a different method of input, for example a mouse or
    > joystick.
    >
    > In the dictionary of key inputs I could map each input directly to a
    > function. However there is no instance name I can call the function
    > on, as I create a thing, add a brain, and add handlers to the brain
    > like this:
    >
    > player = Thing(26, 16, 'player')
    > player.brain = Brain()
    > player.brain.add_handlers(
    > commandHandler(player.brain, player),
    > keyboardHandler(player.brain),
    > fovHandler(player.brain))
    >
    >
    > So what I'm wondering is how to reference the instance in each brain's
    > list of handlers when I want to map something like a key input to a
    > command, or what a better way might be to structure the code.
    >
    >
    >
    >>


    >>player.brain.add_handlers(
    >> commandHandler(player.brain, player),
    >> keyboardHandler(player.brain),
    >> fovHandler(player.brain))


    You're executing commandHandler, and passing its return value into the
    add_handlers() method. So commandHandler is a function, not a method,
    and what is its relationship to anything that actually processes commands?

    Sorry, your pseudo-code is so far from real code that I can't figure out
    what you're doing. So I guess I can't be any help till something else
    turns up to make it clearer. Maybe it's just me.
     
    Dave Angel, May 6, 2009
    #10
  11. George Oliver

    Carl Banks Guest

    On May 5, 7:55 pm, Dave Angel <> wrote:
    > George Oliver wrote:
    > > On May 5, 11:59 am, Dave Angel <> wrote:

    >
    > >> 1) forget about getattr() unless you have hundreds of methods in your
    > >> map.  The real question is why you need two maps. What good is the
    > >> "command string" doing you?   Why not just map the keyvalues directly
    > >> into function objects?

    >
    > > Thanks for the reply Dave. I understand your example and it's what I
    > > originally used. Here is more detail on what I'm doing now, I hope
    > > this will explain my question better.

    >
    > > In the game I'm writing the player, monsters, items and so on are
    > > instances of class Thing, like:

    >
    > > class Thing(object):
    > >     def __init__(self, x, y, name):
    > >         self.x, self.y = x, y
    > >         self.name = name
    > >         self.brain = None

    >
    > > Some Things have an instance of class Brain attached. The Brain
    > > instance has a list of handlers, like:

    >
    > > class Brain(object):
    > >     def __init__(self):
    > >         self.handlers = []

    >
    > > A handler class defines some functionality for the Brain. Each Brain
    > > has an update method like this:

    >
    > > def update(self, arguments):
    > >     for handler in self.handlers:
    > >         handler.update(arguments)

    >
    > > So on each pass through the main game loop, it calls the update method
    > > of all the brains in the game, which run their handler update methods
    > > to change the state of the game.

    >
    > > A handler would be something like a key input handler. The key input
    > > handler is defined separately from the command handler in the case I
    > > want to use a different method of input, for example a mouse or
    > > joystick.

    >
    > > In the dictionary of key inputs I could map each input directly to a
    > > function. However there is no instance name I can call the function
    > > on, as I create a thing, add a brain, and add handlers to the brain
    > > like this:

    >
    > > player = Thing(26, 16, 'player')
    > > player.brain = Brain()
    > > player.brain.add_handlers(
    > >                             commandHandler(player.brain, player),
    > >                             keyboardHandler(player.brain),
    > >                             fovHandler(player.brain))

    >
    > > So what I'm wondering is how to reference the instance in each brain's
    > > list of handlers when I want to map something like a key input to a
    > > command, or what a better way might be to structure the code.

    >
    >  >>
    >
    > >>player.brain.add_handlers(
    > >>                            commandHandler(player.brain, player),
    > >>                            keyboardHandler(player.brain),
    > >>                            fovHandler(player.brain))

    >
    > You're executing commandHandler, and passing its return value into the
    > add_handlers() method.  So commandHandler is a function, not a method,
    > and what is its relationship to anything that actually processes commands?


    It seems to be a factory function.


    > Sorry, your pseudo-code is so far from real code that I can't figure out
    > what you're doing.  So I guess I can't be any help till something else
    > turns up to make it clearer.  Maybe it's just me.


    I think it's you--and probably a lot of other people who haven't ever
    written games. No offense. As someone who's written games before I
    will tell you that George's pseudo-code is not far from real code.
    His overall approach is fairly typical of how games handle input,
    although there are some problems in the details.


    Carl Banks
     
    Carl Banks, May 6, 2009
    #11
  12. George Oliver

    Carl Banks Guest

    On May 5, 12:17 pm, George Oliver <> wrote:
    > A handler would be something like a key input handler. The key input
    > handler is defined separately from the command handler in the case I
    > want to use a different method of input, for example a mouse or
    > joystick.
    >
    > In the dictionary of key inputs I could map each input directly to a
    > function. However there is no instance name I can call the function
    > on, as I create a thing, add a brain, and add handlers to the brain
    > like this:


    What instance do you want to call the functions on? This is the part
    that confuses me.


    > player = Thing(26, 16, 'player')
    > player.brain = Brain()
    > player.brain.add_handlers(
    >                             commandHandler(player.brain, player),
    >                             keyboardHandler(player.brain),
    >                             fovHandler(player..brain))
    >
    > So what I'm wondering is how to reference the instance in each brain's
    > list of handlers when I want to map something like a key input to a
    > command, or what a better way might be to structure the code.



    I'm going to guess that you want the keyboardHandler to call method of
    commandHandler. There's no reason for commandHandler to be a handler
    at all then: keyboardHandler is already handling it.

    So here is how I would change it:

    player = Thing(26,16,'player')
    player.brain = Brain()
    responder = commandResponder(player.brain,player)
    player.brain.add_handlers(
    keyboardHandler(player.brain,responder),
    joystickHandler(player.brain,responder),
    fovHandler(player.brain),
    )


    Carl Banks
     
    Carl Banks, May 6, 2009
    #12
  13. On May 6, 3:07 pm, Carl Banks <> wrote:

    > I'm going to guess that you want the keyboardHandler to call method of
    > commandHandler. There's no reason for commandHandler to be a handler
    > at all then: keyboardHandler is already handling it.



    Thanks Carl, you've got it right and your following example is what I
    ended up using, it's good to know it's a workable solution.
     
    George Oliver, May 7, 2009
    #13
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. ‘5ÛHH575-UAZWKVVP-7H2H48V3
    Replies:
    7
    Views:
    710
    Kanenas
    Feb 15, 2005
  2. Replies:
    2
    Views:
    484
  3. Replies:
    8
    Views:
    514
    Gavin Deane
    Apr 19, 2006
  4. Stephan Wehner
    Replies:
    2
    Views:
    130
    Trans
    Aug 28, 2006
  5. Jeremy Henty
    Replies:
    4
    Views:
    109
    Jeremy Henty
    Nov 21, 2006
Loading...

Share This Page