为什么x,y = zip(* zip(a,b))在Python中起作用?

好的,我喜欢Python的zip()函数。 一直用它,这很棒。 现在我想和zip()做相反的事情,想着“我曾经知道怎么做”,然后google 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中其他令人惊叹的事情是如此神秘和难以谷歌?

Python中的星号logging在Python教程中的Unpacking Argument Lists下 。

星号执行apply (在Lisp和Scheme中已知)。 基本上,它把你的列表,并调用该列表的内容作为参数的function。

这对多个参数也很有用:

 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 

哎呀! 我认为它需要一个头骨来吓跑它工作:

 >>> 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时,返回值被分配给一个variables,从而创build一个列表引用(包含创build的元组列表)。 在第二个调用中,它利用Python自动将列表(或集合?)的返回值打包为多个variables引用的能力,每个引用是单个元组。 如果有人不熟悉在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 

所以它不仅适用于关键字参数(在这个严格的意义上 ),而且也带有命名参数(又名位置参数)。