Pregunta 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 de Python? Por ejemplo, digamos que tengo un módulo foo, y tengo una cadena cuyos contenidos son "bar". Cuál es la mejor manera de llamar foo.bar()?

Necesito obtener el valor de retorno de la función, que es la razón por la que no uso eval. Me di cuenta de 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 haya una forma más elegante de hacerlo.


1185
2017-08-06 03:36


origen


Respuestas:


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

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

En la medida de lo posible, las líneas 2 y 3 se pueden comprimir para:

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

si eso tiene más sentido para tu caso de uso. Puedes usar getattr de esta manera en métodos vinculados a instancia de clase, métodos a nivel de módulo, métodos de clase ... la lista continúa.


1439
2017-08-06 03:57



locals()["myfunction"]()

o

globals()["myfunction"]()

lugareños devuelve un diccionario con una tabla de símbolos local actual. globals devuelve un diccionario con tabla de símbolos global.


401
2018-05-07 12:45



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

module = __import__('foo')
func = getattr(module, 'bar')
func()

240
2017-08-07 11:35



Solo una simple contribución. Si la clase que necesitamos 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')

81
2017-08-19 09:40



Dada una cadena, con un camino completo de python hacia 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()

65
2017-10-16 00:24



La respuesta (espero) que nadie quería

Evalúa el comportamiento similar

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, queremos verificar

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

Necesitamos 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")()

31
2018-04-09 10:17



La mejor respuesta según el Preguntas frecuentes sobre la programación de Python 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


28
2017-10-24 13:20



Por lo que vale, si necesita pasar el nombre de la función (o clase) y el nombre de la aplicación como una cadena, puede hacer esto:

myFnName  = "MyFn"
myAppName = "MyApp"
app = sys.modules[myAppName]
fn  = getattr(app,myFnName)

18
2018-02-14 05:55



Prueba esto. Mientras esto todavía usa eval, solo lo usa para invocar la función desde el contexto actual. Entonces, usted tiene la función real de usar como lo desee.

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

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)

15
2017-12-07 18:29