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
-
1Just 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– Philippe Lavoie2011年02月04日 14:35:19 +00:00Commented Feb 4, 2011 at 14:35
4 Answers 4
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)
2 Comments
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.
2 Comments
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.
1 Comment
Did you try
func = getattr(obj, "method")
if callable(func):
result = func(args)