23

I am trying to pass the name of a function into another function as an argument but I get an error: TypeError: 'str' object is not callable. Here is a simplified example of the problem:

def doIt(a, func, y, z):
    result = z
    result = func(a, y, result)
    return result

def dork1(arg1, arg2, arg3):
    thing = (arg1 + arg2) / arg3
    return thing

def dork2(arg1, arg2, arg3):
    thing = arg1 + (arg2 / arg3)
    return thing

When I call doIt like so:

var = 'dork1'
ned = doIt(3, var, 4, 9)
print (ned)

I get:

Traceback (most recent call last):
   File "<pyshell#9>", line 1, in <module>
     ned = doIt(3, var, 4, 9)
   File "<pyshell#2>", line 3, in doIt
     result = func(a, y, result)
TypeError: 'str' object is not callable
martineau
  • 119,623
  • 25
  • 170
  • 301
Desmond
  • 231
  • 1
  • 2
  • 3
  • 1
    Rock on! globals() worked! Thank you all for your help. – Desmond Jul 28 '10 at 01:06
  • 13
    Noooo! Listen to Alex Martelli! He WROTE python in a nutshell! Don't resort to using an ugly hack that is rarely if ever needed to do something you can do cleanly! Learn to use the language correctly! – jdd Jul 28 '10 at 01:14
  • I think here is the aswear for you problem: [enter link description here](https://stackoverflow.com/questions/3061/calling-a-function-of-a-module-by-using-its-name-a-string) – Łukasz Hawer Apr 13 '22 at 11:41

9 Answers9

30

If you want to pass the function's name, as you said and you're doing, of course you can't call it -- why would one "call a name"? It's meaningless.

If you want to call it, pass the function itself, that is, most emphatically not

var = 'dork1'

but rather

var = dork1

without quotes!

Edit: the OP wonders in a comment (!) how to get a function object given the function name (as a string). As it happens I just showed how to do that in a tutorial I taught at OSCON (from which I'm just back) -- get the slides from here and see page 47, "Lazy-loading callbacks":

class LazyCallable(object):
  def __init__(self, name):
    self.n, self.f = name, None
  def __call__(self, *a, **k):
    if self.f is None:
      modn, funcn = self.n.rsplit('.', 1)
      if modn not in sys.modules:
        __import__(modn)
      self.f = getattr(sys.modules[modn],
                       funcn)
    self.f(*a, **k)

So you could pass LazyCallable('somemodule.dork1') and live happily ever after. If you don't need to deal with the module of course (what a weird architecture that must imply!-) it's easy to adjust this code.

Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • 3
    Desmond might be used to "php-style" function-name passing, which is putting a function name in a string and then passing that around and calling it, where it presumably get's evaled or something. *shudder*. – jdd Jul 28 '10 at 01:05
7

I was thrilled to find this and I don't know if this was answered. My solution to this is as follows:

def doIt(func, *args):
   func_dict = {'dork1':dork1,'dork2':dork2}
   result = func_dict.get(func)(*args)
   return result

def dork1(var1, var2, var3):
   thing = (float(var1 + var2) / var3)
   return thing

def dork2(var1, var2, var3):
   thing = float(var1) + (float(var2) / var3)
   return thing

This can be run as follows:

func = 'dork2'
ned = doIt(func,3, 4, 9)
print ned
user2757128
  • 289
  • 3
  • 3
7

Don't pass the name of a function.

Pass the function.

fun = dork1
ned = doIt(3, fun, 4, 9)
print (ned)
S.Lott
  • 384,516
  • 81
  • 508
  • 779
2
var = 'dork1'
ned = doIt(3, var, 4, 9)
print (ned)

In this example, var is a string. The doIt function "calls" its second argument (for which you pass var). Pass a function instead.

advait
  • 6,355
  • 4
  • 29
  • 39
  • What if I get dork1 from a dictionary value which is stored as a string? How do I convert it to a function "object" (I know that isn't the correct terminology here) rather than a string so I can pass it in correctly? – Desmond Jul 28 '10 at 01:02
  • Check out the `eval()` function: http://docs.python.org/library/functions.html#eval – advait Jul 28 '10 at 01:03
  • 1
    Your dict value should just be the function object: funcs = {'first': dork1, 'second': dork2'} do **not** check out the eval function, unless you are *sure* you need it. and even then, you probably still don't need it. There is almost certainly a better solution. – jdd Jul 28 '10 at 01:06
  • 2
    @jeremiahd is right -- the one good reason for the name-to-function translation which I present is to avoid loading many, many modules in order to set up a system of callbacks (it might slow down startup for no purpose if most of the callbacks may be unneeded in a given run -- lazy loading will "spread the load" beyond just startup time, and only make you "pay for what you use", which in some systems is a good tradeoff). – Alex Martelli Jul 28 '10 at 01:34
2

You probably shouldn't do this, but you can get the function using eval()

for example, to use len,

eval("len")(["list that len is called on"])
Bwmat
  • 4,314
  • 3
  • 27
  • 42
0
def run_function(function_name):
    function_name()

In this example, calling run_function(any_function) will call any_function().

Zenadix
  • 15,291
  • 4
  • 26
  • 41
0

Functions are first-class objects in python. Do this:

var = dork1

If you must pass a string, such as user input, then:

globals()[var]

will look up the function object.

Mark Tolonen
  • 166,664
  • 26
  • 169
  • 251
0
class renderAttributes():
    def __init__(self, name):
        self.name = name
    def decorator_function(self, func_name):
        func_dict = {'my_function': self.my_function}
        def wrapper_function():
            result = func_dict.get(func_name)()
            return result
        return wrapper_function
    def my_function(self):
        //Do whatever you want to do
        return self.name

Then I can create an object of class renderAttributes and call any method defined inside the class by simply passing the function name as below

render_attr_obj = renderAttributes('Bob')
return_function = render_attr_obj.decorator_function('my_function')
return_functon() 
return_function = renderAttributes('Rob')
return_function = render_attr_obj.decorator_function('my_function')
return_functon() 
0

getattr might do the trick, if these functions are a part of a class.

class SomeClass():
    def doIt(self, a, func, y, z):
        result = z
        result = getattr(self, func)(a, y, result)
        return result

    def dork1(self, arg1, arg2, arg3):
        thing = (arg1 + arg2) / arg3
        return thing

    def dork2(self, arg1, arg2, arg3):
        thing = arg1 + (arg2 / arg3)
        return thing

It worked for me when trying to pass function names from sys.argv.

Shoval Sadde
  • 1,152
  • 1
  • 11
  • 11