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
asked Feb 4, 2011 at 14:23
1
  • 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. Commented Feb 4, 2011 at 14:35

4 Answers 4

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)
answered Feb 4, 2011 at 14:29
Sign up to request clarification or add additional context in comments.

2 Comments

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: 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).
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.

answered Feb 4, 2011 at 14:29

2 Comments

you should check if it's callable before : if callable(methodToCall): methodToCall(num)
Thanks! I appreciate the response
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.

answered Feb 4, 2011 at 14:31

1 Comment

Thanks those are some good points. I really appreciate the help.
0

Did you try

func = getattr(obj, "method")
if callable(func):
 result = func(args)
answered Feb 4, 2011 at 14:37

Comments

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.