2010-03-24 160 views
69

好的我爱Python的zip()函数。一直使用它,它很棒。我现在想再做一次与zip()相反的想法,认为“我曾经知道如何做到这一点”,然后google python解压缩,然后记住一个使用这个神奇的*来解压缩一个压缩的元组列表。像这样:为什么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中其他令人惊叹的令人惊叹的事情对谷歌来说如此神秘又难以应付?

+2

重复:http://stackoverflow.com/questions/2233204/how-does-zipitersn-work-in-python – 2010-03-24 21:03:09

+3

噢。这正是问题,虽然,搜索stackoverflow为'zip(*'python不会返回第一页上的重复问题,并搜索'python *'或'python zip(*'不会返回太多,我猜是因为'(*'被忽略了?你说得对,别人也认为这很棒。我应该删除这个问题吗? – 2010-03-24 22:01:33

+1

我不会删除它,因为它因为某种原因在搜索中排名较高。关闭它会允许它作为一个重定向 – 2010-03-24 22:07:43

回答

18

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

+1

Python2系列仍然有一个'应用'功能,但我不认为那里是'*'无法涵盖的任何用例。我相信它已从Python3中删除 – 2010-03-24 21:17:15

+1

@gnibbler:已确认。 'apply'在http://www.python.org/dev/peps/pep-0361/上列出,标题为“在Py3k中删除的功能警告:' – MatrixFrog 2010-03-24 21:42:07

+2

仅适用,因为星号稍后添加。 – DasIch 2010-03-27 19:21:44

8

它也是有用的多ARGS:

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 

糟糕!我认为它需要一个头骨它吓唬工作:

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

在python3我想你需要

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

因为拉链现在返回一个生成函数,而不是假-Y。

+0

或者只是使用一个生成器'unzipped_x =(z [0]用于z压缩)''。如果'zipped'本身就是一个生成器,那么首先将它转换为一个列表,这样就可以再次遍历'unzipped_y'。 'zip(* zip)'没有额外的成本,因为后者在解包参数的过程中也将'zipped'转换为列表。 – 2017-09-25 15:47:31

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 
相关问题