Python 3.0 - dict方法返回视图 - 为什么?

时间:2008-12-04 14:56:11

标签: python-3.x dictionary iterator language-features dictview

  

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

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

对我来说这似乎并不直观,也就是说,我要求列出一些东西(给我所有的钥匙),然后我又回来了。这会让人感到困惑吗?

3 个答案:

答案 0 :(得分:13)

您正在有效地获取列表。它不是内部列表的副本,而是表现为列表但只代表内部状态的东西。

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

主要原因是,对于许多用例而言,返回一个完全独立的列表是不必要和浪费的。这需要复制整个内容(可能或许多内容不多)。

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

答案 1 :(得分:6)

Joachim Sauer的回答很好地解释了为什么list没有被退回。但是这就留下了一个问题,为什么这些函数不会返回迭代器,就像在Python 2中那样iteritems等。

迭代器比容器更具限制性。例如,迭代器不允许多次传递;如果你尝试第二次传球,你会发现它是空的。因此,容器支持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的比较速度有多快。

答案 2 :(得分:0)

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

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