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.

È stato utile?

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 .

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