Chiama una funzione con un elenco di argomenti in Python
Domanda
Sto cercando di chiamare una funzione all'interno di un'altra funzione in Python, ma non riesco a trovare la sintassi corretta. Quello che voglio fare è qualcosa del genere:
def wrapper(func, args):
func(args)
def func1(x):
print(x)
def func2(x, y, z):
return x+y+z
wrapper(func1, [x])
wrapper(func2, [x, y, z])
In questo caso la prima chiamata funzionerà e la seconda no. Quello che voglio modificare è la funzione wrapper e non le funzioni chiamate.
Soluzione
Per espandere un po 'le altre risposte:
Nella riga:
def wrapper(func, *args):
Il * accanto a args
significa " prendi il resto dei parametri dati e li mette in un elenco chiamato args
" ;.
Nella riga:
func(*args)
Il * accanto a args
qui significa " prendi questo elenco chiamato args e 'scartalo' nel resto dei parametri.
Quindi puoi fare quanto segue:
def wrapper1(func, *args): # with star
func(*args)
def wrapper2(func, args): # without star
func(*args)
def func2(x, y, z):
print x+y+z
wrapper1(func2, 1, 2, 3)
wrapper2(func2, [1, 2, 3])
In wrapper2
, l'elenco viene passato esplicitamente, ma in entrambi i wrapper args
contiene l'elenco [1,2,3]
.
Altri suggerimenti
Il modo più semplice per avvolgere una funzione
func(*args, **kwargs)
... è scrivere manualmente un wrapper che chiamerebbe func () al suo interno:
def wrapper(*args, **kwargs):
# do something before
try:
return func(*a, **kwargs)
finally:
# do something after
In Python la funzione è un oggetto, quindi puoi passarne il nome come argomento di un'altra funzione e restituirlo. Puoi anche scrivere un generatore di wrapper per qualsiasi funzione anyFunc () :
def wrapperGenerator(anyFunc, *args, **kwargs):
def wrapper(*args, **kwargs):
try:
# do something before
return anyFunc(*args, **kwargs)
finally:
#do something after
return wrapper
Si noti inoltre che in Python quando non si conoscono o non si desidera nominare tutti gli argomenti di una funzione, è possibile fare riferimento a una tupla di argomenti, che è indicata dal suo nome, preceduta da un asterisco in le parentesi dopo il nome della funzione:
*args
Ad esempio, puoi definire una funzione che accetta qualsiasi numero di argomenti:
def testFunc(*args):
print args # prints the tuple of arguments
Python prevede un'ulteriore manipolazione degli argomenti delle funzioni. È possibile consentire a una funzione di accettare argomenti per parole chiave. All'interno del corpo della funzione gli argomenti delle parole chiave sono contenuti in un dizionario. Tra parentesi dopo il nome della funzione questo dizionario è indicato da due asterischi seguiti dal nome del dizionario:
**kwargs
Un esempio simile che stampa il dizionario degli argomenti delle parole chiave:
def testFunc(**kwargs):
print kwargs # prints the dictionary of keyword arguments
Puoi usare la sintassi * args e ** kwargs per argomenti a lunghezza variabile.
Cosa significano * args e ** kwargs?
E dal tutorial ufficiale di Python
http://docs.python.org /dev/tutorial/controlflow.html#more-on-defining-functions
La risposta letterale alla tua domanda (per fare esattamente quello che hai chiesto, cambiando solo il wrapper, non le funzioni o le chiamate di funzione) è semplicemente di modificare la linea
func(args)
da leggere
func(*args)
Questo dice a Python di prendere la lista fornita (in questo caso, args
) e passarne il contenuto alla funzione come argomenti posizionali.
Questo trucco funziona su entrambi i lati " " della chiamata di funzione, quindi una funzione definita come questa:
def func2(*args):
return sum(args)
sarebbe in grado di accettare tutti gli argomenti posizionali che ci passi e inserirli tutti in un elenco chiamato args
.
Spero che questo aiuti a chiarire un po 'le cose. Nota che questo è possibile anche con argomenti dicts / keyword, usando **
invece di *
.
Devi usare gli argomenti per decomprimere ..
def wrapper(func, *args):
func(*args)
def func1(x):
print(x)
def func2(x, y, z):
print x+y+z
wrapper(func1, 1)
wrapper(func2, 1, 2, 3)
Una piccola aggiunta alle risposte precedenti, poiché non sono riuscito a trovare una soluzione a un problema, che non vale la pena aprire una nuova domanda, ma mi ha portato qui.
Ecco un piccolo frammento di codice, che combina list
, zip ()
e * args
, per fornire un wrapper in grado di gestire una quantità sconosciuta di funzioni con una quantità sconosciuta di argomenti.
def f1(var1, var2, var3):
print(var1+var2+var3)
def f2(var1, var2):
print(var1*var2)
def f3():
print('f3, empty')
def wrapper(a,b, func_list, arg_list):
print(a)
for f,var in zip(func_list,arg_list):
f(*var)
print(b)
f_list = [f1, f2, f3]
a_list = [[1,2,3], [4,5], []]
wrapper('begin', 'end', f_list, a_list)
Tieni presente che zip ()
non fornisce un controllo di sicurezza per elenchi di lunghezza diversa, vedi zip iteratori che affermano di uguale lunghezza in pitone .