2010-03-24 6 views
69

OK Я люблю Python's zip() функции. Используйте его все время, это блестяще. Время от времени я хочу сделать противоположное от zip(), думаю, «я знал, как это сделать», а затем google python unzip, а затем помните, что он использует этот магический *, чтобы разархивировать zipped список кортежей. Например:Почему x, y = zip (* zip (a, b)) работает в 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) 

Что происходит дальше? Что это за волшебная звездочка? Где еще это можно применить и какие другие удивительные вещи в Python настолько загадочны и трудны для Google?

+2

Дубликат: http://stackoverflow.com/questions/2233204/how-does-zipitersn-work-in-python –

+3

о да. Это как раз проблема, но поиск stackoverflow для 'zip (*' python не возвращает дублированный вопрос на первой странице, а googling для 'python *' или 'python zip (*' не возвращает много, я думаю, потому что '(*' игнорируется? Вы правы, но кто-то еще подумал, что это было потрясающе. Должен ли я удалить вопрос? –

+1

Я бы не удалял его, поскольку он по какой-то причине занимает более высокое место в поиске. он должен быть перенаправлен –

ответ

18

Звездочка выполняет apply (как известно в Лиспе и Схеме). В основном, он принимает ваш список и вызывает функцию с содержимым этого списка в качестве аргументов.

+1

Серия Python2 по-прежнему имеет 'apply', но я не думаю, что там являются любыми вариантами использования, которые не могут быть покрыты '*'. Я считаю, что он был удален из Python3 –

+1

@gnibbler: Подтверждено. 'apply' указан в http://www.python.org/dev/peps/pep-0361/ под заголовком' Warnings для функций, удаленных в Py3k: ' – MatrixFrog

+2

Применить только существует, потому что звездочка была добавлена ​​позже. – DasIch

8

Это также полезно для нескольких аргументов:

def foo(*args): 
    print args 

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

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

И, вы можете использовать двойные звездочки для ключевых аргументов и словарей:

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} 

И, конечно же, вы можете объединить эти:

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

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

Довольно аккуратный и полезный материал.

6

Это не всегда работает:

>>> 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 

Oops! Я думаю, что она нуждается в череп, чтобы напугать его в работоспособное:

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

В Python3 я думаю, что вам нужно

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

так зип теперь возвращает функцию генератора, которая не является Ложно-у.

+0

Или просто используйте генератор 'unzipped_x = (z [0] для z в zipped)'. Если 'zipped' сам является генератором, тогда сначала преобразуйте его в список, чтобы снова выполнить повторную процедуру для' unzipped_y'. Нет никакой дополнительной стоимости по сравнению с 'zip (* zipped)', потому что последняя также конвертирует 'zipped' в список в процессе распаковки аргументов. –

0

Добавление к @ bcherry отвечают:

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

Так это работает не только с аргументами ключевого слова (в this strict sense), но с именованными аргументами тоже (иначе позиционные аргументов).

2

Я чрезвычайно новичок в Python, так что это совсем недавно сбило меня с толку, но ему пришлось больше поработать с тем, как был представлен пример и что было подчеркнуто.

Что дало мне проблемы с пониманием примера zip, была асимметрия при обработке возвращаемых значений zip-запроса. То есть, когда zip вызывается в первый раз, возвращаемое значение присваивается одной переменной, тем самым создавая ссылку на список (содержащий созданный список кортежей). Во втором вызове используется возможность Python автоматически распаковывать возвращаемое значение списка (или коллекции?) В несколько ссылок на переменные, причем каждая ссылка является отдельным кортежем. Если кто-то не знаком с тем, как это работает на Python, это облегчает потерю того, что происходит на самом деле.

>>> 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 
Смежные вопросы