2010-07-28 11 views
11

Estoy tratando de pasar el nombre de una función a otra función como argumento, pero me sale un error: "TypeError: 'str' object no se puede llamar". Aquí es un ejemplo simplificado del problema:Python: Pasar un nombre de función como argumento en una función

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 

Cuando llamo doIT así:

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

me sale:

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 
+1

Rock on! globals() funcionó! Gracias por toda tu ayuda. – Desmond

+10

Noooo! ¡Escucha a Alex Martelli! ¡ESCRIBIÓ a Python en pocas palabras! ¡No recurras a usar un hack feo que rara vez o nunca se necesita para hacer algo que puedes hacer limpiamente! Aprende a usar el idioma correctamente! – jeremiahd

Respuesta

24

Si desea pasar el nombre de la función , como dijiste y estás haciendo, por supuesto no puedes llamarlo, ¿por qué uno "llamaría al "? No tiene sentido

Si quieres llamarlo, pasar a la función en sí, es decir, con mayor énfasis no

var = 'dork1' 

sino

var = dork1 

sin comillas!

Editar: OP se pregunta en un comentario (!) Cómo obtener un objeto de función dado el nombre de la función (como una cadena). Da la casualidad que acaba de aparecer como hacer eso en un tutorial enseñé en OSCON (de la que sólo estoy de vuelta) - obtener las diapositivas de here y vea la página 47, "Lazy devoluciones de llamada de carga":

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) 

Así podría pasar LazyCallable('somemodule.dork1') y vivir felices para siempre. Si no necesita lidiar con el módulo por supuesto (¡qué arquitectura tan extraña debe implicar!) Es fácil ajustar este código.

+2

Desmond se puede usar para pasar el nombre de la función "php-style", que es poner un nombre de función en una cadena y luego pasarlo y llamarlo, donde es probable que lo evadan o algo así. *estremecimiento*. – jeremiahd

4

No pase el nombre de una función.

Pase la función.

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

En este ejemplo, var es una cadena. La función doIt "llama" a su segundo argumento (para el que pasa var). Pase una función en su lugar.

+0

¿Qué pasa si obtengo dork1 de un valor de diccionario que está almacenado como una cadena? ¿Cómo lo convierto en una función "objeto" (sé que no es la terminología correcta aquí) en lugar de una cadena para poder pasarla correctamente? – Desmond

+0

Eche un vistazo a la función 'eval()': http://docs.python.org/library/functions.html#eval – advait

+1

Su valor dict debe ser simplemente el objeto de función: funcs = {'first': dork1, 'segundo': dork2 '} do ** not ** echa un vistazo a la función eval, a menos que esté * seguro * la necesite. e incluso entonces, probablemente aún no lo necesites. Es casi seguro que hay una mejor solución. – jeremiahd

0

Las funciones son objetos de primera clase en python. Haga lo siguiente:

var = dork1 

Si tiene que pasar una cadena, tales como la entrada del usuario, entonces:

globals()[var] 

buscará el objeto función.

1

Es probable que no debe hacer esto, pero se puede obtener usando la función eval()

por ejemplo, utilizar len,

eval("len")(["list that len is called on"]) 
1

estaba encantada de encontrar esto y yo no' Saber si esto fue respondido. Mi solución para esto es la siguiente:

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 

Esto se puede ejecutar de la siguiente manera:

func = 'dork2' 
ned = doIt(func,3, 4, 9) 
print ned 
+0

Buena solución, pero esto no servirá como una solución genérica para el problema de OP. –

0
def run_function(function_name): 
    function_name() 

En este ejemplo, llamando run_function(any_function) llamará any_function().

+0

¿Cómo verifica si existe una función? –

+0

La llamada a la función arroja 'NameError' o' AttributeError' si la función no existe. Solo capte esas excepciones. – Zenadix

Cuestiones relacionadas