[英]Why does x,y = zip(*zip(a,b)) work in Python?
OK I love Python's zip()
function. Use it all the time, it's brilliant.好的,我喜欢 Python 的zip()
function。一直用它,它很棒。 Every now and again I want to do the opposite of zip()
, think "I used to know how to do that", then google python unzip, then remember that one uses this magical *
to unzip a zipped list of tuples.我时不时地想做与zip()
相反的事情,想想“我以前知道怎么做”,然后谷歌 python 解压缩,然后记住有人使用这个神奇的*
来解压缩元组的压缩列表。 Like this:像这样:
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)
What on earth is going on?这到底是怎么回事? What is that magical asterisk doing?那个神奇的星号在做什么? Where else can it be applied and what other amazing awesome things in Python are so mysterious and hard to google? Python 中还有哪些其他神奇的东西如此神秘且难以谷歌?
Python 中的星号记录在 Python 教程的Unpacking Argument Lists 下。
The asterisk performs apply
(as it's known in Lisp and Scheme).星号执行apply
(正如在 Lisp 和 Scheme 中所知)。 Basically, it takes your list, and calls the function with that list's contents as arguments.基本上,它接受您的列表,并使用该列表的内容作为参数调用该函数。
It's also useful for multiple args:它对多个 args 也很有用:
def foo(*args):
print args
foo(1, 2, 3) # (1, 2, 3)
# also legal
t = (1, 2, 3)
foo(*t) # (1, 2, 3)
And, you can use double asterisk for keyword arguments and dictionaries:并且,您可以对关键字参数和字典使用双星号:
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}
And of course, you can combine these:当然,你可以结合这些:
def foo(*args, **kwargs):
print args, kwargs
foo(1, 2, a=3, b=4) # (1, 2) {'a': 3, 'b': 4}
Pretty neat and useful stuff.非常整洁和有用的东西。
It doesn't always work:它并不总是有效:
>>> 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!哎呀! I think it needs a skull to scare it into working:我认为它需要一个头骨来吓唬它工作:
>>> unzipped_x, unzipped_y = zip(*zipped) or ([], [])
>>> unzipped_x
[]
>>> unzipped_y
[]
In python3 I think you need在python3中我认为你需要
>>> unzipped_x, unzipped_y = tuple(zip(*zipped)) or ([], [])
since zip now returns a generator function which is not False-y.因为 zip 现在返回一个不是 False-y 的生成器函数。
I'm extremely new to Python so this just recently tripped me up, but it had to do more with how the example was presented and what was emphasized.我对 Python 非常陌生,所以这最近让我感到困惑,但它必须对示例的呈现方式和强调的内容做更多的事情。
What gave me problems with understanding the zip example was the asymmetry in the handling of the zip call return value(s).给我理解 zip 示例的问题是在处理 zip 调用返回值时的不对称性。 That is, when zip is called the first time, the return value is assigned to a single variable, thereby creating a list reference (containing the created tuple list).也就是说,当第一次调用 zip 时,将返回值分配给单个变量,从而创建一个列表引用(包含创建的元组列表)。 In the second call, it's leveraging Python's ability to automatically unpack a list (or collection?) return value into multiple variable references, each reference being the individual tuple.在第二次调用中,它利用 Python 的能力将列表(或集合?)返回值自动解包为多个变量引用,每个引用都是单独的元组。 If someone isn't familiar with how that works in Python, it makes it easier to get lost as to what's actually happening.如果有人不熟悉 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
Addendum to @bcherry's answer: @bcherry 回答的附录:
>>> def f(a2,a1):
... print a2, a1
...
>>> d = {'a1': 111, 'a2': 222}
>>> f(**d)
222 111
So it works not just with keyword arguments (in this strict sense ), but with named arguments too (aka positional arguments).所以它不仅适用于关键字参数( 严格意义上),还适用于命名参数(又名位置参数)。
(x, y) == tuple(zip(*zip(x,y)))
is true if and only if the two following statements are true: (x, y) == tuple(zip(*zip(x,y)))
为真当且仅当以下两个陈述为真:
x
and y
have the same length x
和y
的长度相同x
and y
are tuples x
和y
是元组One good way to understand what's going on is to print at each step:了解正在发生的事情的一种好方法是在每一步打印:
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))))
Which outputs:哪些输出:
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')]
Basically this is what happens:基本上是这样的:
x
and y
are paired according to their respective indexes.来自x
和y
项目根据它们各自的索引配对。(1, 2, 3)
来自所有输入的第一项配对: (1, 2, 3)
('a', 'b', 'c')
来自所有输入的第二项配对:( ('a', 'b', 'c')
Now you can understand why (x, y) == tuple(zip(*zip(x,y)))
is false in this case:现在你可以理解为什么(x, y) == tuple(zip(*zip(x,y)))
在这种情况下是假的:
y
is longer than x
, the first zip operation removed the extra item from y
(as it couldn't be paired), this change is obviously repercuted on the second zipping operation由于y
比x
,第一个 zip 操作从y
删除了额外的项目(因为它无法配对),此更改显然会在第二个压缩操作中重新执行zip
does pair items in tuples and not in lists类型不同,一开始我们有两个列表,现在我们有两个元组,因为zip
元组中的项目配对而不是列表中的项目If you're not 100% certain to understand how zip
work, I wrote an answer to this question here: Unzipping and the * operator如果您不是 100% 确定了解zip
如何工作的,我在这里写了这个问题的答案:解压缩和 * 运算符
x,y = zip(*zip(a,b)) this is using for unzipping two list print(x,y) x,y are different two list x,y = zip(*zip(a,b)) 这用于解压缩两个列表 print(x,y) x,y 是不同的两个列表
If you want to zip list as a tuples or dictionary如果要将列表压缩为元组或字典
https://www.copilotcode.com/2021/12/how-to-zip-to-list-as-tuple-or-as.html https://www.copilotcode.com/2021/12/how-to-zip-to-list-as-tuple-or-as.html
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.