Reputation: 173
I'm relatively new to python and would like to make a class that has a dictionary that corresponds to different methods in the class. I currently have :
class Test:
functions = {"Test1":test1, "Test2":test2}
def test1(self, arg1):
print "test1"
def test2(self, arg1):
print "test2" + arg1
def call_me(self, arg):
self.functions[arg](arg)
Then in my main.py I have the following:
from Test import Test
t = Test()
t.call_me('Test1')
When I call this function I get an error saying name test1 is not defined. Can anyone tell me what I am doing wrong? Any help would be greatly appreciated.
Upvotes: 4
Views: 9897
Reputation: 434
I realise that this is an old question, but I was looking for help and came across it so I thought I would include an answer for future searchers....
What I wanted to (a) group some private functions under a class, and (b) use a dictionary to choose which function to call at run-time. The step I was missing was to make each method a static method. The prototype below shows the functionality:
class Test():
@staticmethod
def Foo():
return 1
@staticmethod
def Baa():
return 2
my_dict = {"foo_val": Foo,"baa_val": Baa}
def __init__(self):
pass
to call it I use
my_funct = Test()
print(my_funct.my_dict["baa_val"]())
Upvotes: 0
Reputation: 366213
You've got multiple problems here.
First, in this line:
functions = {"Test1":test1, "Test2":test2}
At the time Python executes this line of code, there is nothing called test1
or test2
, so you're going to get an immediate NameError
. If you want to do things this way, you're going to have define functions
after all of the functions have been defined, not before.
Next, on the same line, test1
and test2
at this point are plain-old functions. But you're trying to call them as if they were methods, with the magic self
and everything. That isn't going to work. If you understand how methods work, it should be obvious that you can work around this in the call_me
method:
def call_me(self, arg): self.functions[arg].__get__(self, type(self))(arg)
(In this case, you can also get away with just explicitly passing self
as an extra argument. But make sure you understand why before doing that.)
Finally, you're trying to call call_me
with the function test1
, instead of the name 'Test1'
. Presumably the whole reason you've created this mapping is so that you can use the names (dynamically, as strings), so let's actually use them:
t.call_me('Test1')
Note that if the only reason you can't use getattr
is that the runtime names you want to look up aren't the same as the method names you want to define, you can always have a map of strings to strings, and look up the resulting strings with getattr
, which avoids all the other problems here. Borrowing from aruisdante's answer, adding in the name lookup and remembering to pass arg
:
functions = {"Test1": "test1", "Test2": "test2"}
def call_me(self, arg):
return getattr(self, self.functions[arg])(arg)
Upvotes: 7
Reputation: 9115
You need string quotes around your argument, and the T needs to be capitalized:
t.call_me('Test1')
However, python already has the functionality you're trying to replicate built into it via the getattr
method. I.E. you can just do:
def call_me(self, arg):
return getattr(self, arg)()
Note that in this case, the name must be exactly the same as the method name or it will raise an AttributeError
, so it would be:
t.call_me('test1')
UPDATE
So now that you've edited your question, it's clear what the problem is:
class Test:
functions = {"Test1":test1, "Test2":test2}
This is defining functions
at the static/class scope. At this point, test1
and test2
haven't actually been created yet, and they aren't bound to a class instance (so no way to know what self
should be). The 'correct' solution if you wanted to have arbitrary mappings (so getattr
doesn't fit the bill) would be to move this inside an __init__()
:
class Test:
def __init__(self):
self._functions = {"Test1":self.test1, "Test2":self.test2}
def call_me(self, arg):
return self._functions[arg](arg)
Upvotes: 7
Reputation: 102942
In your dict, "Test1"
and "Test2"
are capitalized, while the corresponding functions are not. Change the dict keys to lowercase and everything should work.
Upvotes: 0