这个Python魔法是什么?

时间:2017-06-21 14:09:47

标签: python dictionary

如果你这样做{k:v for k,v in zip(*[iter(x)]*2)} x是一个列表,你会得到一个字典,其中包含所有奇数元素作为键,甚至作为它们的值。哇!

>>> x = [1, "cat", "hat", 35,2.5, True]
>>> d = {k:v for k,v in zip(*[iter(x)]*2)}
>>> d
{1: "cat", "hat": 35, 2.5: True}

我基本了解字典理解是如何工作的,zip如何工作,*如何提取参数,[iter(x)]*2如何连接列表的两个副本,所以我期待一个像{1: 1, "cat": "cat" ...}这样的一对一通信。

这里发生了什么?

2 个答案:

答案 0 :(得分:6)

这肯定是一段有趣的小代码!它可能没有预料到的主要因素是对象实际上是通过引用传递的(它们实际上是passed by assignment,但是嘿)。 iter()构造一个对象,因此“复制”它(在列表中使用乘法,在这种情况下)不会创建一个新对象,而是添加另一个对同一个的引用。这意味着你有一个列表,l[0]是一个迭代器,l[1]相同的迭代器 - 访问它们都访问同一个对象。

每次访问迭代器的下一个元素时,它都会继续它最后一次停止的位置。由于元素在zip()创建的元组的第一个和第二个元素之间交替访问,因此单个迭代器的状态在元组中的两个元素之间都是高级的。

在那之后,字典理解只会消耗这些对元组,因为它们扩展到k, v - 就像在任何其他字典理解中一样。

答案 1 :(得分:5)

这个iter(x)在迭代(列表或类似的)x上创建一个迭代器。使用[iter(x)]*2复制此迭代器。现在你有两次相同迭代器的列表。这意味着,如果我向其中一个人询问一个值,另一个(相同的)也会增加。

zip()现在通过zip(* ... )语法获得两个参数(它们相同)作为两个参数。这意味着,它创建了一个由它得到的两个参数对的列表。它将向第一个迭代器询问一个值(并接收x[0]),然后它会向另一个迭代器询问一个值(并接收x[1]),然后它将形成一对两个值并且把它放在它的输出中。然后它会反复执行此操作,直到迭代器耗尽为止。这样,它将形成一对x[2]x[3],然后是一对x[4]x[5]等。

然后将这个对列表传递给字典理解,这将把对形成为字典的键/值。

易于阅读可能是这样的:

{ k: v for (k, v) in zip(x[::2], x[1::2]) }

但这可能效率不高。