13

dict 方法 dict.keys()、dict.items() 和 dict.values() 返回“视图”而不是列表。 http://docs.python.org/dev/3.0/whatsnew//3.0.html

首先,视图与迭代器有何不同?其次,这种变化有什么好处?仅仅是出于性能原因吗?

这对我来说似乎并不直观,即,我要一份东西清单(把你所有的钥匙给我),然后我又得到了别的东西。这会让人们感到困惑吗?

4

3 回答 3

15

你实际上得到了一份清单。它只是不是内部列表的副本,而是充当列表但仅代表内部状态的东西。

这与它在 Java 中实现的方式相同(可能还有许多其他语言/环境)。

主要原因是对于许多用例来说,返回一个完全分离的列表是不必要且浪费的。它需要复制整个内容(可能很多,也可能不多)。

如果您只是想遍历键,则无需创建新列表。如果您确实需要它作为单独的列表(作为副本),那么您可以轻松地从视图中创建该列表。

于 2008-12-04T14:59:04.603 回答
6

Joachim Sauer 的回答很好地解释了为什么list不返回 a 。但这留下了一个问题,为什么这些函数不会返回迭代器,就像iteritemsPython 2 中的 etc. 那样。

迭代器比容器更具限制性。例如,一个迭代器不允许超过一次传递;如果你尝试第二遍,你会发现它是空的。因此,容器支持诸如此类的操作elem in cont,但迭代器不支持:一旦您检查一个元素是否在迭代器中,迭代器就会被销毁!

另一方面,获取容器通常需要制作副本,例如从字典的键中创建一个列表。

view对象具有两全其美的优点:它充当容器,但不会复制字典!事实上,它是一种通过链接到底层字典来工作的虚拟只读容器。我不知道它是否在标准 Python 中的其他任何地方都可以看到。

编辑:

@AntonyHatchkins:它不返回生成器函数的原因是它不允许快速in操作。是的,in适用于生成器函数(当你调用它们时)。也就是说,您可以这样做:

def f():
  for i in range(10):
    yield i

5 in f() # True

但是根据 的定义in,如果右边是生成器,python 会遍历n生成器的所有项——导致O(n)时间复杂度。您对此无能为力,因为这是任意生成器唯一有意义的行为。

另一方面,在字典视图的情况下,您可以实现in任何您喜欢的方式,因为您对所管理的数据了解得更多。实际上是使用哈希表in实现的复杂性。O(1)您可以通过运行检查它

>>> d = dict(zip(range(50000000), range(50000000)))
>>> 49999999 in d
True
>>> 49999999 in iter(d) # kinda how generator function would work
True
>>>

并注意到第一个in与第二个相比有多快in

于 2012-01-26T18:53:12.993 回答
0

正如在相关问题中已经提到的那样,视图具有len()迭代器缺少的方法(但列表有)。

返回视图而不是列表的另一个好处是,至少对于键而言,它在 O(1) 操作中优化了成员资格测试,而不是列表(或迭代器)的 O(N)。

于 2014-10-24T17:44:11.490 回答