Llamar a una función de un módulo usando su nombre (una cadena)


Cuál es la mejor manera de llamar a una función dada una cadena con el nombre de la función en un programa Python. Por ejemplo, digamos que tengo un módulo foo, y tengo una cadena cuyo contenido es "bar". ¿Cuál es la mejor manera de llamar foo.bar()?

Necesito obtener el valor de retorno de la función, por lo que no solo uso eval. Descubrí cómo hacerlo usando eval para definir una función temporal que devuelve el resultado de esa llamada a la función, pero espero que hay una forma más elegante de hacer esto.

 1244
Author: Claus Wilke, 2008-08-06

10 answers

Asumiendo el módulo foo con el método bar:

import foo
method_to_call = getattr(foo, 'bar')
result = method_to_call()

En cuanto a eso, las líneas 2 y 3 se pueden comprimir a:

result = getattr(foo, 'bar')()

Si eso tiene más sentido para su caso de uso. Puede usar getattr de esta manera en métodos enlazados a instancias de clase, métodos a nivel de módulo, métodos de clase... la lista continúa.

 1510
Author: Patrick Johnmeyer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-22 18:10:17
locals()["myfunction"]()

O

globals()["myfunction"]()

Locals devuelve un diccionario con una tabla de símbolos local actual. globals devuelve un diccionario con una tabla de símbolos global.

 414
Author: sastanin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-07 12:45:13

La solución de Patrick es probablemente la más limpia. Si también necesita recoger dinámicamente el módulo, puede importarlo como:

module = __import__('foo')
func = getattr(module, 'bar')
func()
 253
Author: HS.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-22 18:08:23

Solo una simple contribución. Si la clase que necesitamos como instancia está en el mismo archivo, podemos usar algo como esto:

# Get class from globals and create an instance
m = globals()['our_class']()

# Get the function (from the instance) that we need to call
func = getattr(m, 'function_name')

# Call it
func()

Por ejemplo:

class A:
    def __init__(self):
        pass

    def sampleFunc(self, arg):
        print('you called sampleFunc({})'.format(arg))

m = globals()['A']()
func = getattr(m, 'sampleFunc')
func('sample arg')

# Sample, all on one line
getattr(globals()['A'](), 'sampleFunc')('sample arg')

Y, si no es una clase:

def sampleFunc(arg):
    print('you called sampleFunc({})'.format(arg))

globals()['sampleFunc']('sample arg')
 86
Author: Sourcegeek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-09-22 21:49:18

Dada una cadena, con una ruta completa de python a una función, así es como obtuve el resultado de dicha función:

import importlib
function_string = 'mypackage.mymodule.myfunc'
mod_name, func_name = function_string.rsplit('.',1)
mod = importlib.import_module(mod_name)
func = getattr(mod, func_name)
result = func()
 67
Author: ferrouswheel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-10-16 00:24:22

La respuesta (espero) que nadie ha querido

Comportamiento similar a la evaluación

getattr(locals().get("foo") or globals().get("foo"), "bar")()

¿Por qué no agregar la importación automática

getattr(
    locals().get("foo") or 
    globals().get("foo") or
    __import__("foo"), 
"bar")()

En caso de que tengamos diccionarios adicionales que queremos comprobar

getattr(next((x for x in (f("foo") for f in 
                          [locals().get, globals().get, 
                           self.__dict__.get, __import__]) 
              if x)),
"bar")()

Tenemos que ir más profundo

getattr(next((x for x in (f("foo") for f in 
              ([locals().get, globals().get, self.__dict__.get] +
               [d.get for d in (list(dd.values()) for dd in 
                                [locals(),globals(),self.__dict__]
                                if isinstance(dd,dict))
                if isinstance(d,dict)] + 
               [__import__])) 
        if x)),
"bar")()
 33
Author: 00500005,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-04-09 10:17:41

La mejor respuesta de acuerdo con el Python programming FAQ sería:

functions = {'myfoo': foo.bar}

mystring = 'myfoo'
if mystring in functions:
    functions[mystring]()

La principal ventaja de esta técnica es que las cadenas no necesitan coincidir con los nombres de las funciones. Esta es también la técnica principal utilizada para emular una construcción de caso

 30
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-24 13:20:46

Por si sirve de algo, si necesita pasar el nombre de la función (o clase) y el nombre de la aplicación como una cadena, entonces podría hacer esto:

myFnName  = "MyFn"
myAppName = "MyApp"
app = sys.modules[myAppName]
fn  = getattr(app,myFnName)
 19
Author: trubliphone,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-14 05:55:36

Nada de lo que se sugirió me ayudó. Sin embargo, descubrí esto.

<object>.__getattribute__(<string name>)(<params>)

Estoy usando python 2.66

Espero que esto ayude

 15
Author: Natdrip,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-28 16:56:45

Prueba esto. Mientras que esto todavía usa eval, solo lo usa para invocar la función desde el contexto actual. Después de eso, usted tiene la función real de utilizar como desee.

El principal beneficio para mí de esto es que obtendrá cualquier error relacionado con la evaluación en el punto de invocar la función. Entonces obtendrá solo los errores relacionados con la función cuando llame.

def say_hello(name):
    print 'Hello {}!'.format(name)

# get the function by name
method_name = 'say_hello'
method = eval(method_name)

# call it like a regular function later
args = ['friend']
kwargs = {}
method(*args, **kwargs)
 14
Author: tvt173,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-08 18:09:50