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 fooy tengo una cadena cuyo contenido es "bar". Cual es la mejor forma de llamar foo.bar()?

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

preguntado el 06 de agosto de 08 a las 01:08

14 Respuestas

Suponiendo módulo foo con metodo bar:

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

Puede acortar las líneas 2 y 3 a:

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

si eso tiene más sentido para su caso de uso.

Puedes usar el getattr de esta manera en métodos ligados a instancia de clase, métodos a nivel de módulo, métodos de clase ... la lista continúa.

Respondido 09 Oct 19, 21:10

Se puede usar hasattr o getattr para determinar si una función está definida. Tenía un mapeo de base de datos (eventType y manejo de functionName) y quería asegurarme de que nunca "olvidé" definir un controlador de eventos en mi python - Shaun

Esto funciona si ya conoce el nombre del módulo. Sin embargo, si desea que el usuario proporcione el nombre del módulo como una cadena, esto no funcionará. - Blairg23

Si necesita evitar una excepción NoneType no invocable, también puede emplear la forma de tres argumentos de getattr: getattr (foo, 'bar', lambda: None). Pido disculpas por el formato; la aplicación de Android stackexchange es aparentemente terrible. - geekofalltrades

Consulte también la respuesta proporcionada por @sastanin si solo le interesan, por ejemplo, las funciones de su módulo local / actual. - NuSkooler

@akki Sí, si eres in el foo módulo que puedes usar globals() para hacer esto: methodToCall = globals()['bar'] - ben hoyt

locals()["myfunction"]()

or

globals()["myfunction"]()

locales devuelve un diccionario con una tabla de símbolos local actual. globales devuelve un diccionario con una tabla de símbolos global.

contestado el 07 de mayo de 09 a las 13:05

Este método con globals / locals es bueno si el método que necesita llamar está definido en el mismo módulo desde el que está llamando. - joelmob

@Joelmob ¿hay alguna otra forma de obtener un objeto por cadena fuera del espacio de nombres raíz? - Nick t

@NickT Solo conozco estos métodos, no creo que haya otros que cumplan la misma función que estos, al menos no puedo pensar en una razón por la que debería haber más. - joelmob

Tengo una razón para ti (en realidad, lo que me llevó aquí): el módulo A tiene una función F que necesita llamar a una función por su nombre. El Módulo B importa el Módulo A e invoca la función F con una solicitud para llamar a la Función G, que está definida en el Módulo B. Esta llamada falla porque, aparentemente, la función F solo se ejecuta con los globales que están definidos en el Módulo F, por lo que globals () ['G'] = Ninguno. - david stein

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

Respondido 22 Feb 17, 18:02

No entiendo ese último comentario. __import__ tiene su propio derecho y la siguiente oración en los documentos mencionados dice: "El uso directo de __import __ () es raro, excepto en los casos en los que desea importar un módulo cuyo nombre solo se conoce en tiempo de ejecución". Entonces: +1 para la respuesta dada. - hoffmaje

Utiliza importlib.import_module. Los documentos oficiales dicen sobre __import__: "Esta es una función avanzada que no es necesaria en la programación diaria de Python, a diferencia de importlib.import_module ()". docs.python.org/2/library/functions.html#__import__ - deslumbrante

@glarrain Siempre que esté de acuerdo con solo el soporte 2.7 y superior. - Xiong Chiamiov

@Xiong Chaimiov, importlib.import_module es compatible con 3.6. Ver docs.python.org/3.6/library/… - colineador

@cowlinator Sí, 3.6 es parte de "2.7 y versiones posteriores", tanto en la semántica de control de versiones estricta como en las fechas de lanzamiento (llegó unos seis años después). Tampoco existió durante tres años después de mi comentario. ;) En la rama 3.x, el módulo existe desde 3.1. 2.7 y 3.1 son ahora bastante antiguos; todavía encontrará servidores que solo admiten 2.6, pero probablemente valga la pena que importlib sea el consejo estándar hoy en día. - Xiong Chiamiov

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

Respondido el 22 de Septiembre de 14 a las 22:09

Dada una cadena, con una ruta de Python completa 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()

Respondido 16 Oct 13, 01:10

Eso me ayudó. Es una versión ligera de __import__ función. - pankaj bhambhani

Creo que esta fue la mejor respuesta. - Saeid

La mejor respuesta según el Preguntas frecuentes sobre programación en Python sería:

functions = {'myfoo': foo.bar}

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

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

Respondido 24 Oct 16, 14:10

La respuesta (espero) que nadie quiso nunca

Evaluar como comportamiento

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

Respondido 09 Abr '14, 11:04

Esto podría mejorarse escaneando de forma recursiva el árbol de directorios y montando automáticamente las unidades USB. Wilks

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)

Respondido 14 Feb 12, 05:02

Un poco más genérico es handler = getattr(sys.modules[__name__], myFnName) - lony

Prueba esto. Si bien esto todavía usa eval, solo lo usa para convocar la función del contexto actual. Entonces, tienes la función real para usarla como desees.

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ás , solamente los errores relacionados con la función cuando llamas.

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)

Respondido el 08 de diciembre de 16 a las 18:12

Esto sería arriesgado. string puede tener cualquier cosa y eval terminaría evaluándolo sin ninguna consideración. - iankit

Claro, debe tener en cuenta el contexto en el que lo está utilizando, ya sea que sea apropiado o no, dados esos riesgos. - tvt173

Una función no debería ser responsable de validar sus parámetros; ese es el trabajo de una función diferente. Decir que es arriesgado usar eval con una cadena es decir que el uso de cada función es arriesgado. - red777

Nunca deberías usar eval a menos que sea estrictamente necesario. getattr(__module__, method_name) es una opción mucho mejor en este contexto. - moi

nada de lo que se sugirió me ayudó. Aunque descubrí esto.

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

Estoy usando python 2.66

Espero que esto ayude

Respondido el 28 de diciembre de 12 a las 16:12

¿En qué aspecto es esto mejor que getattr ()? - V13

Exactamente lo que quería. ¡Funciona de maravilla! ¡¡Perfecto!! self.__getattribute__('title') es igual a self.title - ioaniatr

self.__getattribute__('title') no funciona en ningún caso (no sé por qué) después de todo, pero func = getattr(self, 'title'); func(); lo hace. Entonces, tal vez sea mejor usar getattr() en lugar de - ioaniatr

¿Pueden las personas que no conocen Python dejar de votar esta basura? Usar getattr en lugar de. - Aran Fey

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

El escenario es que, un método en una clase quiere llamar a otro método en la misma clase dinámicamente, he agregado algunos detalles al ejemplo original que ofrece un escenario más amplio 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()

Salida (Python 3.7.x)

función1: 12

función2: 12

Respondido 19 Abr '19, 21:04

Aunque getattr () es un método elegante (y aproximadamente 7 veces más rápido), puede obtener el valor de retorno de la función (local, método de clase, módulo) con eval tan elegante como x = eval('foo.bar')(). Y cuando implementas algún manejo de errores, entonces de manera bastante segura (el mismo principio se puede usar para getattr). Ejemplo con importación y clase de módulo:

# import module, call module function, pass parameters and print retured value with eval():
import random
bar = 'random.randint'
randint = eval(bar)(0,100)
print(randint) # will print random int from <0;100)

# also class method returning (or not) value(s) can be used with eval: 
class Say:
    def say(something='nothing'):
        return something

bar = 'Say.say'
print(eval(bar)('nice to meet you too')) # will print 'nice to meet you' 

Cuando el módulo o la clase no existe (error tipográfico o algo mejor), se genera NameError. Cuando la función no existe, se genera AttributeError. Esto se puede usar para manejar errores:

# try/except block can be used to catch both errors
try:
    eval('Say.talk')() # raises AttributeError because function does not exist
    eval('Says.say')() # raises NameError because the class does not exist
    # or the same with getattr:
    getattr(Say, 'talk')() # raises AttributeError
    getattr(Says, 'say')() # raises NameError
except AttributeError:
    # do domething or just...
    print('Function does not exist')
except NameError:
    # do domething or just...
    print('Module does not exist')

Respondido 16 Jul 20, 16:07

getattr llama al método por su nombre desde un objeto. Pero este objeto debería ser padre de la clase de llamada. La clase principal se puede obtener mediante super(self.__class__, self)

class Base:
    def call_base(func):
        """This does not work"""
        def new_func(self, *args, **kwargs):
            name = func.__name__
            getattr(super(self.__class__, self), name)(*args, **kwargs)
        return new_func

    def f(self, *args):
        print(f"BASE method invoked.")

    def g(self, *args):
        print(f"BASE method invoked.")

class Inherit(Base):
    @Base.call_base
    def f(self, *args):
        """function body will be ignored by the decorator."""
        pass

    @Base.call_base
    def g(self, *args):
        """function body will be ignored by the decorator."""
        pass

Inherit().f() # The goal is to print "BASE method invoked."

Respondido 01 Jul 20, 09:07

Esta es una respuesta simple, esto le permitirá limpiar la pantalla, por ejemplo. Hay dos ejemplos a continuación, con eval y exec, que imprimirán 0 en la parte superior después de la limpieza (si está usando Windows, cambie clear a cls, Los usuarios de Linux y Mac lo dejan como está, por ejemplo) o simplemente lo ejecutan, respectivamente.

eval("os.system(\"clear\")")
exec("os.system(\"clear\")")

Respondido 28 ago 19, 17:08

Esto no es lo que pide op. - Tuncay Göncüoğlu

este fragmento de código contiene las 2 peores fallas de seguridad, anidadas. Algún tipo de récord. - Jean-François Fabre ♦

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.