1

I am trying to call a function in a class based on the string I passed in.

I tried following the steps at this link: Calling a function of a module from a string with the function's name in Python

Here is my code:

methodNameString = "add" + typeOfShip
methodToCall = getattr(listOfPlayerFleets[currentPlayer], methodNameString)

listOfPlayerFleets[currentPlayer].methodToCall(num)

I get the error:

AttributeError:fleet instance has no attribute 'methodToCall'

Any ideas as to why methodToCall isn't being assigned my correct method name?

I also tried

methodToCall = getattr(fleet, methodToCall)

then I get the message:

AttributeError: 'module' object has no attribute 'addCruiser'

Its as if the getattr can't find my methods in my class.

the listOfPlayerFleets is a list of fleet objects

Here is what the fleet object looks like you can see the methods do really exist.

class fleet:
    """ Stores Fleet Numbers, Represents a fleet """

    ships = {'fighters':0, 'cruisers':0, 'capitols':0}
    attacking = False
    defending = False

    def __init__(self):
        self.ships = {'fighters':0, 'cruisers':0, 'capitols':0}
        self.attacking = False
        self.defending = False

    #add a Fighter
    def addFighter(self, numOfFighters):
        self.ships['fighters'] = numOfFighters


    #add a Cruiser
    def addCruiser(self, numOfCruisers):
        self.ships['cruisers'] = numOfCruisers

    #add a Capitol Ship
    def addCapitol(self, numOfCapitols):
        self.ships['capitols'] = numOfCapitols
Community
  • 1
  • 1
ChickenFur
  • 2,360
  • 3
  • 20
  • 26
  • 1
    Just so you know, your addShip function actually replace the number of ship, it do not add them. You might want rename it to setShip or something. – Philippe Lavoie Feb 04 '11 at 14:35

4 Answers4

3

Your methodToCall variable is a bound method, meaning you don't need to call it on an object--it knows the object it will be called on. fleet.addFighter, for example, is an unbound method. Printing repr(methodToCall) and repr(fleet.addFighter) should make this clear.

You should use this:

methodNameString = "add" + typeOfShip
methodToCall = getattr(listOfPlayerFleets[currentPlayer], methodNameString)

methodToCall(num)
robert
  • 33,242
  • 8
  • 53
  • 74
  • Hey that worked great! Thanks! Much better then this other solution I tried. eval("listOfPlayerFleets[currentPlayer]." + methodNameString + "(" + str(num) + ")") which worked but I hear eval isn't your friend. – ChickenFur Feb 04 '11 at 14:33
  • @ChickenFur: Calling methods (and getting attributes) by strings "is not your friend" either, it's just not as widely preached (perhaps because many other languages don't bother to provide seperate functions for it but leave no choice but `eval`). –  Feb 04 '11 at 14:35
2

That should do it.

methodNameString = "add" + typeOfShip
methodToCall = getattr(listOfPlayerFleets[currentPlayer], methodNameString)

methodToCall(num)

The getattr gives you a reference to the method of that specific instance (listOfPlayerFleets[currentPlayer]), so just call it with the parameters.

Reiner Gerecke
  • 11,936
  • 1
  • 49
  • 41
1

First off, this kind of thing is rarely on par with a proper solution, e.g. using dictionary, and even less rarely superior to those. You sould propably have a method addShip(kind, num) that just does self.ships[kind] += num. Much cleaner, easier to extend, DRY (don't repeat yourself) and as an extra bonus also faster.

As for the errors: listOfPlayerFleets[currentPlayer].methodToCall(num) tries to call the method called methodToCall (which obviously doesn't exist. getattr(listOfPlayerFleets[currentPlayer], methodNameString) already got you the method you want, and it's a bound method, i.e. when you call methodToCall(), the right self is passed.

The other error ('method' object has no ...) is because there's a difference between modules and the things (e.g. classes) contained in it. I suppose the class fleet is in a module called fleet? Then you need fleet.fleet. By the way, classes should be named in CamelCase - see the style guide, PEP 8.

0

Did you try

func = getattr(obj, "method")
if callable(func):
  result = func(args)
Philippe Lavoie
  • 2,583
  • 5
  • 25
  • 39