Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling python dictionary of function from class

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.

like image 355
user3766476 Avatar asked Dec 12 '22 02:12

user3766476


1 Answers

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)
like image 113
abarnert Avatar answered Jan 12 '23 08:01

abarnert