2010-03-24 16 views
69

OK Me encanta la función zip() de Python. Úselo todo el tiempo, es brillante. De vez en cuando quiero hacer lo contrario de zip(), pensar "Yo solía saber cómo hacer eso", entonces google python descomprimir, luego recuerda que uno usa este mágico * para descomprimir una lista comprimida de tuplas. De esta manera:¿Por qué x, y = zip (* zip (a, b)) funcionan en Python?

x = [1,2,3] 
y = [4,5,6] 
zipped = zip(x,y) 
unzipped_x, unzipped_y = zip(*zipped) 
unzipped_x 
    Out[30]: (1, 2, 3) 
unzipped_y 
    Out[31]: (4, 5, 6) 

¿Qué demonios está pasando? ¿Qué está haciendo ese asterisco mágico? ¿Dónde más se puede aplicar y qué otras cosas increíbles en Python son tan misteriosas y difíciles de buscar en Google?

+2

duplicado: http://stackoverflow.com/questions/2233204/how-does-zipitersn-work-in-python –

+3

oh sí. Sin embargo, este es exactamente el problema, al buscar stackoverflow para 'zip (*' python no devuelve la pregunta duplicada en la primera página, y buscar 'python *' o 'python zip (*' no devuelve mucho, supongo porque el '(*' es ignorado? Tienes razón, alguien más también pensó que esto era increíble. ¿Debo eliminar la pregunta? –

+1

No lo eliminaría, ya que ocupa un lugar más alto en la búsqueda por algún motivo. Cerrarlo permitiría sirve para redirigir. –

Respuesta

18

El asterisco realiza apply (como se lo conoce en Lisp y Scheme). Básicamente, toma su lista y llama a la función con el contenido de esa lista como argumentos.

+1

La serie Python2 todavía tiene una 'aplicar' la función, pero no creo que haya son casos de uso que no pueden ser cubiertos por '*'. Creo que se ha eliminado de Python3 –

+1

@gnibbler: confirmado. 'apply' se enumera en http://www.python.org/dev/peps/pep-0361/ debajo del encabezado' Advertencias para las características eliminadas en Py3k: ' – MatrixFrog

+2

Aplicar solo existe porque el asterisco se agregó más tarde. – DasIch

8

También es útil para múltiples argumentos:

def foo(*args): 
    print args 

foo(1, 2, 3) # (1, 2, 3) 

# also legal 
t = (1, 2, 3) 
foo(*t) # (1, 2, 3) 

Y, puede usar doble asterisco para los argumentos de palabras clave y los diccionarios:

def foo(**kwargs): 
    print kwargs 

foo(a=1, b=2) # {'a': 1, 'b': 2} 

# also legal 
d = {"a": 1, "b": 2} 
foo(**d) # {'a': 1, 'b': 2} 

Y, por supuesto, se pueden combinar estas:

def foo(*args, **kwargs): 
    print args, kwargs 

foo(1, 2, a=3, b=4) # (1, 2) {'a': 3, 'b': 4} 

Bastante ordenado y útil.

6

No siempre funciona:

>>> x = [] 
>>> y = [] 
>>> zipped = zip(x, y) 
>>> unzipped_x, unzipped_y = zip(*zipped) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: need more than 0 values to unpack 

Ups! Creo que necesita un cráneo para asustar en funcionamiento:

>>> unzipped_x, unzipped_y = zip(*zipped) or ([], []) 
>>> unzipped_x 
[] 
>>> unzipped_y 
[] 

En python3 creo que es necesario

>>> unzipped_x, unzipped_y = tuple(zip(*zipped)) or ([], []) 

desde cremallera devuelve ahora una función de generador que no es falso-y.

+0

O simplemente use un generador 'unzipped_x = (z [0] para z en comprimido)'. Si 'zip 'es en sí mismo un generador, primero conviértalo en una lista para que puedas iterar nuevamente para' unzipped_y'. No hay un costo adicional frente a 'zip (* zip)' porque este último también convierte 'zip' a una lista en el proceso de desempaquetar los argumentos. –

0

Adición a la respuesta de @ bcherry:

>>> def f(a2,a1): 
... print a2, a1 
... 
>>> d = {'a1': 111, 'a2': 222} 
>>> f(**d) 
222 111 

Por lo que no funciona sólo con los argumentos de palabras clave (en this strict sense), pero con argumentos con nombre también (aka posicionales argumentos).

2

Soy extremadamente nuevo en Python, por lo que esto me acabó de hacer tropezar recientemente, pero tenía que ver más con cómo se presentaba el ejemplo y qué se hacía hincapié.

Lo que me dio problemas para entender el ejemplo zip fue la asimetría en el manejo del valor (s) de devolución de llamada zip. Es decir, cuando se llama a zip la primera vez, el valor de retorno se asigna a una sola variable, creando así una referencia de lista (que contiene la lista de tuplas creada). En la segunda convocatoria, aprovecha la capacidad de Python para desempaquetar automáticamente un valor de retorno de la lista (¿o de la colección?) En múltiples referencias de variables, siendo cada referencia la tupla individual. Si alguien no está familiarizado con la forma en que funciona en Python, es más fácil perderse en lo que está sucediendo realmente.

>>> x = [1, 2, 3] 
>>> y = "abc" 
>>> zipped = zip(x, y) 
>>> zipped 
[(1, 'a'), (2, 'b'), (3, 'c')] 
>>> z1, z2, z3 = zip(x, y) 
>>> z1 
(1, 'a') 
>>> z2 
(2, 'b') 
>>> z3 
(3, 'c') 
>>> rezipped = zip(*zipped) 
>>> rezipped 
[(1, 2, 3), ('a', 'b', 'c')] 
>>> rezipped2 = zip(z1, z2, z3) 
>>> rezipped == rezipped2 
True