2012-08-09 31 views
5
def f1(n): #accepts one argument 
    pass 

def f2(): #accepts no arguments 
    pass 

FUNCTION_LIST = [(f1,(2)), #each list entry is a tuple containing a function object and a tuple of arguments 
       (f1,(6)), 
       (f2,())] 

for f, arg in FUNCTION_LIST: 
    f(arg) 

La terza volta nel ciclo, tenta di passare una tupla vuota di argomenti a una funzione che non accetta argomenti. Dà l'errore TypeError: f2() takes no arguments (1 given). Le prime due chiamate di funzione funzionano correttamente: viene inviato il contenuto della tupla, non la tupla stessa.Python - elenco di funzioni/argomento tuple

sbarazzarsi del tupla vuota di argomenti nella voce della lista incriminata non risolve il problema:

FUNCTION_LIST[2] = (f2,) 
for f,arg in FUNCTION_LIST: 
    f(arg) 

risultati in ValueError: need more than 1 value to unpack.

Ho anche provato a ripetere l'indice piuttosto che gli elementi della lista.

for n in range(len(FUNCTION_LIST)): 
    FUNCTION_LIST[n][0](FUNCTION_LIST[n][1]) 

Questo dà lo stesso TypeError nel primo caso, e IndexError: tuple index out of range quando la terza voce della lista è (f2,).

Infine, la notazione asterisco non funziona. Questa volta gli errori sulla chiamata a f1:

for f,args in FUNCTION_LIST: 
    f(*args) 

TypeError: f1() argument after * must be a sequence, not int.

Ho esaurito le cose da provare. Penso ancora che il primo dovrebbe funzionare. Qualcuno può indicarmi la giusta direzione?

risposta

8

Il tuo commento in questo frammento di codice mostra un equivoco rilevante in questo contesto:

FUNCTION_LIST = [(f1,(2)), #each list entry is a tuple containing a function object and a tuple of arguments 
       (f1,(6)), 
       (f2,())] 

Le espressioni (2) e (6) non sono tuple - sono numeri interi. Dovresti usare (2,) e (6,) per indicare le tuple a elemento singolo che desideri. Dopo aver sistemato questo, il codice del ciclo dovrebbe essere così:

for f, args in FUNCTION_LIST: 
    f(*args) 

Vedi Unpacking Argument Lists nel tutorial Python per una spiegazione della sintassi *args.

+0

Grazie per l'ottima risposta.Domanda corollaria: è possibile eseguire operazioni sul valore di ritorno delle funzioni? Diciamo che volevo raddoppiare la prima voce: 'FUNCTION_LIST = [(f1 * 2, (2,)), (f1, (6,)), (f2,())]' non funzionerebbe, lo farebbe, perché dovresti provare ad applicare l'operatore di moltiplicazione a una funzione _oggetto_, non il valore restituito dalla funzione. –

+0

In relazione a quanto segue: è possibile chiamare altre funzioni nella tupla degli argomenti, che verrebbe valutata quando viene chiamata la funzione? 'FUNCTION_LIST = [(f1, (time.time(),)), (f1, (6,)), (f2,())]' non mi darebbe qualcosa in base al tempo, perché la chiamata al tempo. time() verrebbe valutato quando l'elenco è popolato. –

+1

@poorsod: per l'esecuzione ritardata, è necessario definire le funzioni facendo ciò che si desidera. Ad esempio 'def double_f1 (x): return 2 * f1 (x)' o 'def f1_time(): return f1 (time.time)'. In alcuni casi, puoi farcela con le funzioni di 'lambda', ma ti consiglio di usarlo con parsimonia. –

0

Provare a passare *() anziché (). Il simbolo * dice a python di decomprimere l'iterabile che lo segue, in modo da decomprimere la tupla vuota e passare nulla alla funzione, poiché la tupla era vuota.

2

Il problema è che tale notazione:

(6) 

viene valutata al valore intero ed è necessario tuple, in modo da scrivere in questo modo:

(6,) 

e la vostra notazione asterisco avrà successo.

0

Per la cronaca, una buona alternativa che ho scoperto è l'uso di functools.partial. Il seguente codice fa quello che stavo cercando di fare:

from functools import partial 

def f1(n): #accepts one argument 
    pass 

def f2(): #accepts no arguments 
    pass 

FUNCTION_LIST = [partial(f1,2), #each list entry is a callable with the argument pre-ordained 
       partial(f1,6), 
       partial(f2)] #the call to partial is not really necessary for the entry with no arguments. 

for f in FUNCTION_LIST: f()