Chiamare una funzione di un modulo utilizzando il suo nome (una stringa)

voti
1k

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

Ho bisogno di ottenere il valore di ritorno della funzione, che è il motivo per cui non mi basta usare eval. Ho capito come farlo utilizzando evalper definire una funzione di temperatura che restituisce il risultato di questa chiamata di funzione, ma spero che ci sia un più elegante modo per farlo.

È pubblicato 06/08/2008 alle 02:36
fonte dall'utente
In altre lingue...                            


12 risposte

voti
1k

Modulo assumendo foocon metodo bar:

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

Quanto che va, linee 2 e 3 possono essere compressi per:

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

se questo ha più senso per il vostro caso d'uso. È possibile utilizzare getattrin questo modo sui metodi legati istanza di classe, metodi a livello di modulo, metodi di classe ... l'elenco potrebbe continuare.

Risposto il 06/08/2008 a 02:57
fonte dall'utente

voti
229

La soluzione di Patrick è probabilmente il più pulito. Se è necessario scegliere dinamicamente il modulo così, è possibile importarlo come:

module = __import__('foo')
func = getattr(module, 'bar')
func()
Risposto il 07/08/2008 a 10:35
fonte dall'utente

voti
387
locals()["myfunction"]()

o

globals()["myfunction"]()

gente del posto restituisce un dizionario con una corrente tabella dei simboli locale. globali restituisce un dizionario con tabella dei simboli globali.

Risposto il 07/05/2009 a 11:45
fonte dall'utente

voti
18

Per quello che vale, se è necessario passare alla funzione (o classe) e denominazioni app come una stringa, allora si potrebbe fare questo:

myFnName  = "MyFn"
myAppName = "MyApp"
app = sys.modules[myAppName]
fn  = getattr(app,myFnName)
Risposto il 14/02/2012 a 03:55
fonte dall'utente

voti
77

Basta un semplice contributo. Se la classe che abbiamo bisogno di istanza è nello stesso file, possiamo usare qualcosa di simile a 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 una classe:

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

globals()['sampleFunc']('sample arg')
Risposto il 19/08/2012 a 08:40
fonte dall'utente

voti
13

niente di tutto ciò che è stato proposto mi ha aiutato. Ho fatto scoprire questo però.

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

Sto usando python 2.66

Spero che questo ti aiuti

Risposto il 28/12/2012 a 14:56
fonte dall'utente

voti
64

Data una stringa, un percorso completo di pitone a una funzione, questo è come sono andato circa ottenere il risultato di detta 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()
Risposto il 15/10/2013 a 23:24
fonte dall'utente

voti
30

La risposta (spero) che nessuno mai desiderato

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 dizionari aggiuntivi vogliamo verificare

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")()
Risposto il 09/04/2014 a 09:17
fonte dall'utente

voti
26

La migliore risposta in base alla 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 corrispondere ai nomi delle funzioni. Questa è anche la tecnica principale utilizzata per emulare un costrutto case

Risposto il 24/10/2016 a 12:20
fonte dall'utente

voti
15

Prova questo. Anche se questo usa ancora eval, utilizza solo per evocare la funzione dal contesto attuale . Quindi, si ha la funzione reale di utilizzare come si desidera.

Il vantaggio principale per me da questo è che si avrà nessuna errori eval relativi al punto di evocare la funzione. Poi si aprirà solo gli errori e correlate alla funzione quando si chiama.

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)
Risposto il 07/12/2016 a 16:29
fonte dall'utente

voti
0

Come questa domanda Come chiamare in modo dinamico i metodi all'interno di una classe utilizzando il metodo di assegnazione nome ad una variabile [duplicato] contrassegnato come un duplicato come questo, sto inviando una risposta correlata qui:

Lo scenario è, un metodo in una classe desidera chiamare un altro metodo sulla stessa classe in modo dinamico, ho aggiunto qualche dettaglio per esempio originale che offre alcuni 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 (3.7.x Python)

funzione1: 12

function2: 12

Risposto il 26/03/2019 a 16:15
fonte dall'utente

voti
0

Questa è una risposta semplice, questo vi permetterà di cancellare lo schermo, per esempio. Ci sono due esempi che seguono, con eval e exec, che stamperanno 0 in alto dopo la pulizia (se si utilizza Windows, cambiare clearper clsgli utenti Linux e Mac lasciano come è per esempio) o semplicemente eseguirlo, rispettivamente.

eval("os.system(\"clear\")")
exec("os.system(\"clear\")")
Risposto il 28/08/2019 a 18:46
fonte dall'utente

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more