tags:

views:

119

answers:

6

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
+5  A: 

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
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*.
jeremiahd
+2  A: 

Don't pass the name of a function.

Pass the function.

fun = dork1
ned = doIt(3, fun, 4, 9)
print (ned)
S.Lott
+1  A: 
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
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
Check out the `eval()` function: http://docs.python.org/library/functions.html#eval
advait
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.
jeremiahd
@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
A: 

If you have to pass it as a string you can call it with:

globals()['dork1'](arg1,arg2,arg3)
GWW
A: 

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
A: 

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