27

在 Python 2.7 中,字典有一个iterkeys方法和一个viewkeys方法(以及类似的值和项对),提供了两种不同的方法来懒惰地迭代字典的键。该viewkeys方法提供 的主要特征iterkeysiter(d.viewkeys())有效地等效于d.iterkeys()。此外,返回的对象viewkeys具有方便的类似集合的功能。因此,有充分的理由viewkeys支持iterkeys.

另一个方向呢?除了与早期版本的 Python 兼容之外,还有什么iterkeys更好的方法viewkeys吗?总是使用会丢失任何东西viewkeys吗?

4

4 回答 4

21

字典视图会像字典一样更新,而迭代器不一定会这样做。

这意味着如果您使用视图,更改字典,然后再次使用视图,视图将发生更改以反映字典的新状态。

它们提供字典条目的动态视图,这意味着当字典更改时,视图会反映这些更改。 资源

例子:

>>> test = {1: 2, 3: 4}
>>> a = test.iterkeys()
>>> b = test.viewkeys()
>>> del test[1]
>>> test[5] = 6
>>> list(a)
[3, 5]
>>> b
dict_keys([3, 5])

当对大小进行更改时,将引发异常:

>>> test = {1: 2, 3: 4}
>>> a = test.iterkeys()
>>> b = test.viewkeys()
>>> test[5] = 6
>>> list(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration
>>> b
dict_keys([1, 3, 5])

还值得注意的是,您只能对 keyiterator 进行一次迭代:

>>> test = {1: 2, 3: 4}
>>> a = test.iterkeys()
>>> list(a)
[1, 3]
>>> list(a)
[]
>>> b = test.viewkeys()
>>> b
dict_keys([1, 3])
>>> b
dict_keys([1, 3])
于 2012-04-17T10:57:21.583 回答
15

正如您所观察到的,在功能方面,视图更好。兼容性方面,它们更糟。

一些性能指标,取自 64 位 Ubuntu 机器上的 Python 2.7.2:

>>> from timeit import timeit

处理空字典:

>>> emptydict = {}
>>> timeit(lambda: emptydict.viewkeys())
0.24384498596191406
>>> timeit(lambda: list(emptydict.viewkeys()))
0.4636681079864502
>>> timeit(lambda: emptydict.iterkeys())
0.23939013481140137
>>> timeit(lambda: list(emptydict.iterkeys()))
1.0098130702972412

构造视图的成本略高,但使用视图比迭代器快得多(快两倍多一点)。

处理千元字典:

>>> fulldict = {i: i for i in xrange(1000)}
>>> timeit(lambda: fulldict.viewkeys())
0.24295306205749512
>>> timeit(lambda: list(fulldict.viewkeys()))
13.447425842285156
>>> timeit(lambda: fulldict.iterkeys())
0.23759889602661133
>>> timeit(lambda: list(fulldict.iterkeys()))
15.45390510559082

结果相同,但标记较少;构建视图的成本要稍微高一些,但消耗它肯定会更快(快 15%)。

list(dict.viewkeys())为了与and进行公平比较list(dict.iterkeys())dict.keys()明显更快:

>>> timeit(lambda: emptydict.keys())
0.2385849952697754
>>> timeit(lambda: fulldict.keys())
7.842105150222778

总结:这是一个权衡;更好的功能(你将很少使用)和性能(很少会重要到足以让你担心——如果你关心这样的性能问题,你可能已经处于需要使用 numpy/scipy 的区域了) 与更好的兼容性和肌肉记忆使用率相比。

就个人而言,除非已经依赖于仅 2.7 的功能,或者除非我完全控制运行时环境,否则我会避免在 Python 2 代码中使用字典视图。即使在这些情况下,我的手指仍然想输入iter而不是view,所以我让他们!

于 2012-04-17T11:20:11.260 回答
12

不,iterkeysover没有优势viewkeys,就像对它们中的任何一个都没有优势keys一样。iterkeys只是为了向后兼容。事实上,在 Python 3 中,viewkeys是唯一仍然存在的行为,并且它已被重命名为keys- 该viewkeys方法实际上是 Python 3 行为的反向移植。

于 2012-04-17T10:59:52.090 回答
9

正如名称(和文档)所示,viewkeys()viewvalues()方法viewitems()返回字典中当前元素的视图,这意味着如果字典更改,视图也会更改;意见 懒惰的。在一般情况下,视图是类似集合的,只有当值是可散列的时,项目视图才是类似集合的。

在什么情况下使用标准方法会更好keys()values()以及items()?您提到了一个非常重要的问题:向后兼容性。此外,当您需要一个包含所有键、值或项目的简单列表(不是类似集合,不是迭代器)时,当您需要修改返回的列表而不修改原始字典时,以及当您需要快照时字典的键、值或项目在某一时刻,独立于对字典的任何后期修改。

那么和iterkeys()呢?当您需要字典内容的一次性、恒定空间、惰性迭代器快照时,它们是一个合适的选择,它将告诉您字典在迭代时是否被修改(通过 a ),它们对于向后兼容性也非常重要.itervalues()iteritems()RuntimeError

于 2012-04-17T11:10:02.780 回答