Ответ 1
Звездочка в Python документирована в учебнике Python под Распаковка списков аргументов.
OK Я люблю функцию Python zip()
. Используйте его все время, это блестяще. Время от времени я хочу сделать противоположное от zip()
, подумать "я знал, как это сделать", а затем google python unzip, а затем вспомнить, что он использует этот магический *
для распаковки zip-списка кортежей. Вот так:
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?
Звездочка в Python документирована в учебнике Python под Распаковка списков аргументов.
Звездочка выполняет apply
(как известно в Lisp и схеме). В основном, он принимает ваш список и вызывает функцию с содержимым этого списка в качестве аргументов.
Это также полезно для нескольких аргументов:
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}
Довольно аккуратный и полезный материал.
Это не всегда работает:
>>> 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 ([], [])
поскольку zip теперь возвращает функцию-генератор, которая не является False-y.
Я очень новичок в 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
Добавление к ответу @bcherry:
>>> def f(a2,a1):
... print a2, a1
...
>>> d = {'a1': 111, 'a2': 222}
>>> f(**d)
222 111
Таким образом, это работает не только с аргументами ключевого слова (в этом строгом смысле), но и с именованными аргументами (aka позиционными аргументами).
(x, y) == tuple(zip(*zip(x,y)))
является истинным тогда и только тогда, когда два следующих утверждения верны:
x
и y
имеют одинаковую длинуx
и y
кортежиОдин хороший способ понять, что происходит, это печатать на каждом шаге:
x = [1, 2, 3]
y = ["a", "b", "c", "d"]
print("1) x, y = ", x, y)
print("2) zip(x, y) = ", list(zip(x, y)))
print("3) *zip(x, y) = ", *zip(x, y))
print("4) zip(*zip(x,y)) = ", list(zip(*zip(x,y))))
Какие выводы:
1) x, y = [1, 2, 3] ['a', 'b', 'c', 'd']
2) zip(x, y) = [(1, 'a'), (2, 'b'), (3, 'c')]
3) *zip(x, y) = (1, 'a') (2, 'b') (3, 'c')
4) zip(*zip(x,y)) = [(1, 2, 3), ('a', 'b', 'c')]
В основном это то, что происходит:
x
и y
спарены согласно их соответствующим индексам.(1, 2, 3)
('a', 'b', 'c')
Теперь вы можете понять, почему (x, y) == tuple(zip(*zip(x,y)))
ложно в этом случае:
y
длиннее, чем x
, первая операция zip удалила лишний элемент из y
(так как он не может быть спарен), это изменение, очевидно, повторяется во второй операции zipzip
делает пару элементов в кортежах, а не в списках Если вы не на 100% уверены, что понимаете, как работает zip
, я написал ответ на этот вопрос здесь: Распаковка и оператор *