Llamar a una función de un módulo mediante el uso de su nombre (una cadena)

StackOverflow https://stackoverflow.com/questions/3061

  •  08-06-2019
  •  | 
  •  

Pregunta

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

Necesito obtener el valor de retorno de la función, que es por qué no sólo tiene que utilizar eval.Me di cuenta de cómo hacerlo mediante el uso de eval para definir una temp función que devuelve el resultado de la llamada a la función, pero tengo la esperanza de que hay una forma más elegante de hacer esto.

¿Fue útil?

Solución

Suponiendo que el módulo de foo con el método bar:

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

En la medida en que va, líneas 2 y 3 puede ser comprimido a:

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

si que tiene más sentido para el caso de uso.Puede utilizar getattr en esto de la moda en la instancia de la clase los métodos vinculados, de nivel de módulo métodos, los métodos de la clase...la lista continúa.

Otros consejos

locals()["myfunction"]()

o

globals()["myfunction"]()

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

Patricio solución es, probablemente, el más limpio.Si usted necesita de forma dinámica recoger el módulo así, se puede importar como:

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

Sólo una simple contribución.Si la clase que necesitamos instancia está en el mismo archivo, se puede 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 una clase:

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

globals()['sampleFunc']('sample arg')

Dada una cadena, con un python completo de ruta de acceso a una función, esta es la forma en que me fui acerca de cómo obtener 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()

La mejor respuesta de acuerdo a la Programación Python 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 tienen que coincidir los nombres de las funciones.Esta es también la principal técnica utilizada para emular un caso de construcción de

La respuesta (espero) nadie quería

Eval como el comportamiento de la

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

¿Por qué no añadir un auto-importación

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

En caso de que tengamos extra diccionarios 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")()

Para lo que vale, si usted necesita para pasar de la función (o de clase) nombre y el nombre de la aplicación como una cadena, entonces usted podría hacer esto:

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

Intenta esto.Mientras este todavía utiliza eval, que sólo se utiliza para invocar a la función desde el contexto actual.A continuación, tiene la función real para el uso que desee.

El principal beneficio para mí de esto es que usted conseguirá cualquier eval relacionados con errores en el punto de la convocatoria a la función.Entonces usted va a obtener sólo la función de los errores relacionados con el momento de llamar.

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)

nada de lo que se sugirió que me ayudó.Me hizo descubrir este aunque.

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

Estoy usando python 2.66

Espero que esto ayude

Como esta pregunta Cómo dinámicamente llamar a métodos dentro de una clase utilizando el método de asignación de nombre a una variable [duplicar] marcado como un duplicado como este, estoy publicando una relacionados con la respuesta aquí:

El escenario es, un método en una clase desea llamar a otro método de la misma clase de forma dinámica, he añadido algunos detalles, ejemplo original que ofrece algunas de las más amplio escenario y claridad:

class MyClass:
    def __init__(self, i):
        self.i = i

    def get(self):
        func = getattr(MyClass, 'function{}'.format(self.i))
        func(self, 12)   # This one will work
        # self.func(12)    # But this does NOT work.


    def function1(self, p1):
        print('function1: {}'.format(p1))
        # do other stuff

    def function2(self, p1):
        print('function2: {}'.format(p1))
        # do other stuff


if __name__ == "__main__":
    class1 = MyClass(1)
    class1.get()
    class2 = MyClass(2)
    class2.get()

De Salida (Python 3.7.x)

function1:12

function2:12

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top