python - otro - Llamar a una función de un módulo usando su nombre(una cadena)
llamar funcion de otro archivo python (11)
Como esta pregunta Cómo llamar dinámicamente a los métodos dentro de una clase usando la asignación de nombre de método a una variable [duplicado] marcada como duplicada como esta, estoy publicando una respuesta relacionada aquí:
El escenario es, 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 y claridad más amplios:
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
¿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 a
foo.bar()
?
Necesito obtener el valor de retorno de la función, por lo que no solo uso
eval
.
Descubrí cómo hacerlo utilizando
eval
para definir una función temporal que devuelva el resultado de esa llamada de función, pero espero que haya una forma más elegante de hacerlo.
Dada una cadena, con una ruta completa de python a una función, esta es la forma en que traté de 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 según las preguntas frecuentes de 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
La respuesta (espero) que nadie haya querido nunca.
Evaluar como comportamiento
getattr(locals().get("foo") or globals().get("foo"), "bar")()
¿Por qué no agregar auto-importación
getattr(
locals().get("foo") or
globals().get("foo") or
__import__("foo"),
"bar")()
En caso de que tengamos diccionarios extra queremos revisar.
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")()
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()
Nada de lo sugerido me ayudó. Sin embargo, descubrí esto.
<object>.__getattribute__(<string name>)(<params>)
Estoy usando python 2.66
Espero que esto ayude
Para lo que vale la pena, 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)
Prueba esto. Si bien esto todavía usa eval, solo lo usa para invocar la función del contexto actual . Entonces, tienes la función real para usar como quieras.
El principal beneficio para mí de esto es que obtendrás cualquier error relacionado con la evaluación al momento de invocar la función. Entonces solo obtendrás los errores relacionados con la función cuando llames.
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)
Solo una simple aportación. Si la clase que necesitamos para la 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'')
Suponiendo módulo
foo
con
bar
método:
import foo
method_to_call = getattr(foo, ''bar'')
result = method_to_call()
En lo que va, las líneas 2 y 3 se pueden comprimir para:
result = getattr(foo, ''bar'')()
Si eso tiene más sentido para su caso de uso.
Puede utilizar
getattr
de esta manera en los métodos enlazados de instancia de clase, los métodos de nivel de módulo, los métodos de clase ... y la lista continúa.