2012-10-04 16 views
36

Le seguenti opere splendidamente in Python:argomenti disimballaggio: argomenti solo di nome possono seguire * espressione

def f(x,y,z): return [x,y,z] 

a=[1,2] 

f(3,*a) 

Gli elementi di a ottengono scompattato come se si fosse chiamato come f(3,1,2) e restituisce [3,1,2]. Meraviglioso!

Ma io non posso disfare gli elementi della a nei primi due argomenti:

f(*a,3) 

Invece di chiamare che, come f(1,2,3), ottengo "SyntaxError: argomenti solo di nome possono seguire * espressione".

Mi chiedo il motivo per cui deve essere così e se c'è qualche trucco intelligente di cui potrei non essere a conoscenza per decomprimere gli array in parti arbitrarie degli elenchi di argomenti senza ricorrere a variabili temporanee.

+5

'f (* a, 3)' ora funziona in Python 3.5 –

risposta

27

Come Raymond La risposta di Hettinger fa notare che questo potrebbe cambiare è cambiato in Python 3 e here is a related proposal, che è stato accettato. in particolare quelli connessi alla domanda corrente, ecco una delle possibili modifiche a tale proposta che è stato discusso:

Only allow a starred expression as the last item in the exprlist. This would simplify the unpacking code a bit and allow for the starred expression to be assigned an iterator. This behavior was rejected because it would be too surprising.

quindi non ci sono ragioni di attuazione per la restrizione con l'estrazione, gli argomenti delle funzioni, ma è davvero un po 'sorprendente!

Nel frattempo, ecco la soluzione che cercavo, un po 'ovvio, a posteriori:

f(*(a+[3])) 
+3

E se 'a' è una tupla:' f (* (a + (3,))) ' – Hotschke

10

Non è necessario a essere in questo modo. Era solo una regola che Guido scopriva di essere ragionevole.

In Python 3, le regole per l'estrazione, sono stati liberalizzati in qualche modo:

>>> a, *b, c = range(10) 
>>> a 
0 
>>> b 
[1, 2, 3, 4, 5, 6, 7, 8] 
>>> c 
9 

seconda che Guido si sente sarebbe migliorare la lingua, che la liberalizzazione potrebbe essere esteso anche a funzionare argomenti.

Vedere la discussione su extended iterable unpacking per alcuni pensieri sul perché Python 3 ha cambiato le regole.

+1

Interessante! Grazie! Non intendevo esprimerlo come "necessario", ma ero curioso della logica. Sembra che potrebbe essere stato piuttosto arbitrario. Per quanto riguarda una soluzione, sembra 'apply (f, a + [3])' lo farebbe, anche se vedo che apply() è deprecato. – dreeves

+0

Grazie ancora per la spiegazione delucidativo. Vedi anche la mia risposta per ulteriori informazioni su questo e sulla soluzione che stavo cercando. – dreeves

4

f prevede 3 argomenti (x, , z, in questo ordine).

Supponiamo L = [1,2]. Quando chiami f(3, *L), ciò che Python fa dietro le quinte, è quello di chiamare f(3, 1, 2), senza conoscere davvero la lunghezza di L.

Quindi cosa succede se lo L era invece [1,2,3]?

Poi, quando si chiama f(3, *L), si finirà per chiamare f(3,1,2,3), che sarà un errore perché f si aspetta esattamente 3 argomenti e si diede 4.

Ora, supponiamo L=[1,2]1. Look at what happens when you call f`:

>>> f(3,*L) # works fine 
>>> f(*L) # will give you an error when f(1,2) is called; insufficient arguments 

Ora, è implicitamente sa quando si chiama f(*L, 3) che saranno assegnati a z 3, ma Python non lo sa. Sa solo che gli ultimi j elementi dell'input a f saranno definiti dal contenuto di L. Ma dal momento che non conosce il valore di len(L), non può fare ipotesi sul fatto che f(*L,3) abbia il numero corretto di argomenti.

Tuttavia, questo non è il caso di f(3,*L). In questo caso, python sa che tutti gli argomenti TRANNE il primo saranno definiti dal contenuto di L.

Tuttavia, se sono stati denominati argomenti f(x=1, y=2, z=3), gli argomenti a cui viene assegnato il nome verranno prima associati. Solo allora gli argomenti posizionali sono vincolati. Così fai f(*L, z=3). In tal caso, z è associato prima a 3 e quindi gli altri valori vengono associati.

Ora è interessante notare che, se l'avete fatto f(*L, y=3), che darebbe un errore per cercare di assegnare al y due volte (una volta con la parola chiave, ancora una volta con la posizionale)

Spero che questo aiuti

+0

Penso che potrei non essere d'accordo con questo, in particolare la parte "python does not know that". Come dice Raymond Hettinger, sembra essere una restrizione arbitraria. Potrei comunque immaginare un argomento di efficienza contro la liberalizzazione. – dreeves

+0

Possibile. Ho condiviso questa domanda su G +, taggato a Guido. Vediamo se dice qualcosa – inspectorG4dget

2

Nizza. Questo funziona anche per le tuple. Da non dimenticare la virgola:

a = (1,2) 
f(*(a+(3,))) 
+0

Questo è un trucco sporco! –

-1

È possibile utilizzare f(*a, z=3) se si utilizza f(*a, 3), non so come disimballare il parametro per che hai fornito 2 parametri e 2 è il secondo.

Problemi correlati