2012-10-04 32 views
36

Los siguientes trabajos muy bien en Python:argumentos: Extrayendo los argumentos con nombre pueden seguir solamente * expresión

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

a=[1,2] 

f(3,*a) 

Los elementos de a consiguen desembalado como si hubiera llamado él como f(3,1,2) y vuelve [3,1,2]. ¡Maravilloso!

Pero no puedo descomprimir los elementos de a en los primeros dos argumentos:

f(*a,3) 

En lugar de llamar al igual que f(1,2,3), consigo "SyntaxError: argumentos únicamente con nombre pueden seguir * expresión".

Me pregunto por qué tiene que ser así y si hay algún truco inteligente que pueda no ser consciente de desempaquetar matrices en partes arbitrarias de listas de argumentos sin recurrir a variables temporales.

+5

'f (* a, 3)' ahora funciona en Python 3.5 –

Respuesta

27

Como Raymond La respuesta de Hettinger señala que este puede cambiar ha cambiado en Python 3 y here is a related proposal, que ha sido aceptado. especialmente en relación con la pregunta actual, aquí está uno de los posibles cambios en la propuesta que se discutió:

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.

por lo que hay razones de implementación para el desembalaje de restricción con argumentos de la función pero sí es un poco sorprendente!

Mientras tanto, aquí está la solución que estaba buscando, un poco obvio en retrospectiva:

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

Y si 'a' es tuple:' f (* (a + (3,))) ' – Hotschke

10

No tiene que ser así. Era solo una regla que Guido descubrió que era sensato.

En Python 3, las reglas para el desembalaje se han liberalizado algo:

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

Dependiendo de si Guido siente que mejoraría la lengua, que la liberalización también podría extenderse a funcionar argumentos.

Consulte la discusión en extended iterable unpacking para obtener algunas ideas sobre por qué Python 3 cambió las reglas.

+1

¡Interesante! ¡Gracias! No quise decirlo como "tengo que hacerlo", pero tenía curiosidad sobre la justificación. Parece que puede haber sido bastante arbitrario. En cuanto a una solución, parece que 'apply (f, a + [3])' lo haría, aunque veo que apply() está en desuso. – dreeves

+0

Gracias de nuevo por la respuesta elucidante. Ver también mi respuesta para más información sobre esto y la solución alternativa que estaba buscando. – dreeves

4

f esperan 3 argumentos (x, y, z, en ese orden).

Suponer L = [1,2]. Cuando llame al f(3, *L), lo que hace python detrás de escena, es llamar al f(3, 1, 2), sin conocer realmente la longitud de L.

¿Qué ocurre si L fue en su lugar [1,2,3]?

Entonces, cuando se llama f(3, *L), que va a terminar llamando f(3,1,2,3), que será un error porque f está esperando exactamente 3 argumentos y que le dio 4.

Ahora, supongamos 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 

Ahora, usted sabe implícitamente cuando se llama f(*L, 3) que 3 serán asignados a z, pero Python no sabes. Solo se sabe que el último j muchos elementos de la entrada a f se definirá por los contenidos de L. Pero dado que no conoce el valor de len(L), no puede hacer suposiciones sobre si f(*L,3) tendría la cantidad correcta de argumentos. Sin embargo, este no es el caso con f(3,*L). En este caso, Python sabe que todos los argumentos, EXCEPTO el primero, estarán definidos por los contenidos de L.

Pero si ha nombrado los argumentos f(x=1, y=2, z=3), entonces los argumentos asignados por nombre se vincularán primero. Solo entonces están vinculados los argumentos posicionales. Entonces haces f(*L, z=3). En ese caso, z se une primero a 3 y, a continuación, los otros valores quedan vinculados.

Ahora interesante, si lo hizo f(*L, y=3), eso le dará un error para intentar asignar a y dos veces (una vez con la palabra clave, una vez más con la posición)

espero que esto ayude

+0

Creo que puedo estar en desacuerdo con esto, en particular con la parte "python no sabe eso". Como dice Raymond Hettinger, parece ser una restricción arbitraria. Sin embargo, podría imaginar un argumento de eficiencia contra la liberalización. – dreeves

+0

Posible. Compartí esta pregunta en G +, etiquetada a Guido. Veamos si dice algo – inspectorG4dget

2

Niza. Esto también funciona para tuplas. No se olvide la coma:

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

¡Es un truco sucio! –

-1

Puede usar f(*a, z=3) si usa f(*a, 3), no sabe cómo desempaquetar el parámetro porque proporcionó 2 parámetros y 2 es el segundo.

Cuestiones relacionadas