简体   繁体   English

为什么 x,y = zip(*zip(a,b)) 在 Python 中有效?

[英]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 xy的长度相同
  • x and y are tuples xy是元组

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:基本上是这样的:

  1. Items from x and y are paired according to their respective indexes.来自xy项目根据它们各自的索引配对。
  2. Pairs are unpacked to 3 different objects (tuples)对被解包为 3 个不同的对象(元组)
  3. Pairs are passed to zip, which will again, pair every items based on indexes:成对传递给 zip,它会再次根据索引对每个项目进行配对:
    • first items from all inputs are paired: (1, 2, 3)来自所有输入的第一项配对: (1, 2, 3)
    • second items from all inputs are paired: ('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)))在这种情况下是假的:

  • since 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由于yx ,第一个 zip 操作从y删除了额外的项目(因为它无法配对),此更改显然会在第二个压缩操作中重新执行
  • types differ, at start we had two lists, now we have two tuples as 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.

相关问题 R是否等效于python中zip [i,j]中x,y的[x [y]]? - R equivalent of [x[y] for x,y in zip(i,j)] in python? 为什么 if not in(x,y) 在 python 中根本不起作用 - why does if not in(x,y) not work at all in python any([a == b for a, b in zip(string, string[1:])]) 是如何工作的 - how does any([a == b for a, b in zip(string, string[1:])]) work 为什么 print(zip(*A)), 给 output 形式<zip object at 0x7f8ef0f82b48> ,但在执行 set(zip(*A)) 时预期 output? 注意 A 是一个列表</zip> - Why does print(zip(*A)), give output in the form <zip object at 0x7f8ef0f82b48>, but expected output when doing set(zip(*A))? Note that A is a list python中的Zip与列表无法正常工作 - Zip in python does not work properly with lists 为什么zip在Python 2中会占用大量内存? - Why does zip use a lot of memory in Python 2? Python 之禅:错误不应该无声无息地传递。 为什么 zip 的工作方式如此? - Zen of Python: Errors should never pass silently. Why does zip work the way it does? Print()在zip()的&#39;for&#39;循环中不起作用 - Print() does not work in 'for' loop with zip() zip(*[iter(s)]*n) 在 Python 中如何工作? - How does zip(*[iter(s)]*n) work in Python? 为什么 Python zipfile 不能提供与命令行 zip 相同的输出 .zip 文件大小? - Why does Python zipfile not give the same output .zip file size as command-line zip?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM