La chiamata di una funzione di un modulo, utilizzando il suo nome (una stringa)

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

  •  08-06-2019
  •  | 
  •  

Domanda

Qual è il modo migliore per andare su di chiamare una funzione che, data una stringa con il nome di una funzione in un programma in Python.Per esempio, diciamo che ho un modulo foo, e ho una stringa il cui contenuto è "bar".Qual è il modo migliore per chiamare foo.bar()?

Ho bisogno di ottenere il valore di ritorno della funzione, che è il motivo per cui non utilizzo eval.Ho capito come farlo utilizzando eval per definire una temp funzione che restituisce il risultato della chiamata di funzione, ma spero che ci sia un modo più elegante per fare questo.

È stato utile?

Soluzione

Supponendo che il modulo foo con il metodo bar:

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

Per quanto che va, le linee 2 e 3 possono essere compressi per:

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

se che rende più senso per il vostro caso d'uso.È possibile utilizzare getattr in questo modo, su istanza della classe i metodi associati, a livello di modulo metodi, i metodi della classe...la lista continua.

Altri suggerimenti

locals()["myfunction"]()

o

globals()["myfunction"]()

locali restituisce un dizionario con una corrente locale tabella dei simboli. globals restituisce un dizionario con la tabella dei simboli globale.

Patrick soluzione è probabilmente il più pulito.Se si debbono ritirare il modulo, è possibile importarlo come:

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

Un semplice contributo.Se la classe di cui abbiamo bisogno per esempio lo stesso file, si può usare qualcosa come questo:

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

Per esempio:

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

E, se non di una classe:

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

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

Data una stringa, con un completo python percorso di una funzione, questo è come sono andato su come ottenere il risultato di tale funzione:

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 risposta migliore secondo il Programmazione Python FAQ sarebbe:

functions = {'myfoo': foo.bar}

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

Il vantaggio principale di questa tecnica è che le corde non devono coincidere con i nomi delle funzioni.Questa è anche la principale tecnica utilizzata per emulare un costrutto case

La risposta (spero) nessuno ha mai voluto

Eval come comportamento

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

Perché non aggiungere auto-importazione

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

Nel caso In cui abbiamo altri dizionari vogliamo controllare

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

Abbiamo bisogno di andare più in profondità

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

Per quello che vale, se si ha bisogno di passare la funzione (o di classe) nome e il nome dell'app, come una stringa, allora si potrebbe fare così:

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

Prova in questo modo.Mentre questo ancora utilizza la funzione eval, si utilizza solo per evocare la funzione del contesto corrente.Quindi, si ha la reale funzione da utilizzare come si desidera.

Il vantaggio principale per me è che si otterrà alcun eval gli errori relativi al punto di richiamare la funzione.Quindi si ottiene solo la funzione degli errori relativi al momento della chiamata.

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)

nulla di ciò che è stato suggerito, mi ha aiutato.Ho fatto scoprire questo, però.

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

Sto usando python 2.66

Spero che questo aiuta

Come questa domanda Come dinamicamente la chiamata di metodi all'interno di una classe utilizzando il metodo di assegnazione di un nome ad una variabile [duplica] contrassegnato come un duplicato come questo, sto postando una relativa risposta qui:

Lo scenario è, un metodo in una classe di voler chiamare un altro metodo della stessa classe in modo dinamico, ho aggiunto alcuni dettagli, per esempio originale che offre alcune scenario più ampio e chiarezza:

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

Uscita (Python 3.7.x)

funzione1:12

funzione2:12

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top