tags:

views:

142

answers:

6

Hi, everyone. Please see example below. I'd like to supply a string to 'schedule_action' method which specifies, what Bot-class method should be called. In the example below I've represented it as 'bot.action()' but I have no idea how to do it correctly. Please help

class Bot:
    def work(self): pass
    def fight(self): pass

class Scheduler:
    def schedule_action(self,action):
       bot = Bot()
       bot.action()

scheduler = Scheduler()
scheduler.schedule_action('fight')
+6  A: 

In short,

getattr(bot, action)()

getattr will look up an attribute on the object by name -- attributes can be data or member methods The extra () at the end calls the method.

You could get the method in a separate step, like this, as well:

method_to_call = getattr(bot, action)
method_to_call()

And you can pass arguments to the method in the usual way:

getattr(bot, action)(argument1, argument2)

or

method_to_call = getattr(bot, action)
method_to_call(argument1, argument2)
Ian Clelland
+13  A: 

Use getattr:

class Bot:
    def fight(self):
       print "fighting is fun!"

class Scheduler:       
    def schedule_action(self,action):
       bot = Bot()
       getattr(bot,action)()

scheduler = Scheduler()
scheduler.schedule_action('fight')

Note that getattr also takes an optional argument that allows you to return a default value in case the requested action doesn't exist.

Mark Byers
+3  A: 
class Scheduler:
    def schedule_action(self,action):
       bot = Bot()
       boundmethod = getattr(bot, action)
       boundmethod()
Alex Martelli
+1  A: 
def schedule_action(self,action):
         bot = Bot()
         bot.__getattribute__(action)()
prestomation
+6  A: 

I'm not sure if it applies in your situation, but you may consider using a function pointer instead of manipulating the strings.

class Bot:
    def work(self): 
        print 'working'
    def fight(self): 
        print 'fightin'

class Scheduler:
    def schedule_action(self,action):
       bot = Bot()
       action(bot)

scheduler = Scheduler()
scheduler.schedule_action(Bot.fight)
scheduler.schedule_action(Bot.work)

Which prints:

fightin
working

If you can do this, it will give you an error about a misspelled function at compile-time when the code is interpreted instead of during run-time. This could shorten your debug cycle for stupid data-entry errors, especially if the actions are done over a span of time. Nothing sucks more than running something overnight and discovering that you had a syntax error in the morning.

Ross Rogers
Strongly consider this option. If you want to dynamically choose a method to call, this could be the right option for you. Only use the `getattr`-based options if you're generating the name in some convoluted fashion (such as reading it from a file, from a socket, or from user input).
Wesley
True that it will give an error earlier in the situation you described, but the error is not at compile time.
Mark Byers
ah, you're right. post edited.
Ross Rogers
+1  A: 

You can also use a dictionary to map methods to actions. For instance:

ACTIONS = {"fight": Bot.fight,
           "walk": Bot.walk,}

class Scheduler:
    def schedule_action(self, action):
        return ACTIONS[action](Bot())
chromano