对于Python字典,iterkeys是否比viewkey提供任何优势?

For a Python dictionary, does iterkeys offer any advantages over viewkeys?

在Python 2.7,词典有两对和一viewkeysiterkeys法法(和类似的价值观和对项目),提供两种不同的方法iterate懒洋洋地在钥匙字典。酒店提供酒店委托viewkeys法学院iterkeys特征,有效地与iter(d.viewkeys())d.iterkeys()等效。此外,一个方便的对象返回的viewkeys集样的特点。因此,一个有过强的原因是viewkeysiterkeys青睐。

其他的什么方向?除了兼容早期的版本有任何Python的方式),这将是优选的在iterkeysviewkeys?没有什么是失去了通过使用viewkeys总是准时吗?


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

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

They provide a dynamic view on the dictionary’s entries, which means that when the dictionary changes, the view reflects these changes.
Source

例子:

1
2
3
4
5
6
7
8
9
>>> 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])

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

1
2
3
4
5
6
7
8
9
10
>>> 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迭代一次:

1
2
3
4
5
6
7
8
9
10
11
>>> 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])


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

一些性能指标取自64位Ubuntu计算机上的python 2.7.2:

1
>>> from timeit import timeit

处理空字典:

1
2
3
4
5
6
7
8
9
>>> 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

构建视图的成本稍微高一些,但是使用视图的速度要比迭代器快得多(比迭代器快一倍多)。

处理千元素字典:

1
2
3
4
5
6
7
8
9
>>> 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())list(dict.iterkeys())进行公平比较,dict.keys()明显更快:

1
2
3
4
>>> timeit(lambda: emptydict.keys())
0.2385849952697754
>>> timeit(lambda: fulldict.keys())
7.842105150222778

总结:这是一个权衡;更好的功能(您很少使用)和性能(这只会非常不重要,足以让您担心&mdash;如果您关心这些性能问题,您可能已经处于需要与numpy/scipy一起工作的区域),而不是更好的兼容性和肌肉记忆使用。

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


不,与viewkeys相比,iterkeys没有优势,这与keys没有优势。iterkeys只是为了向后兼容。实际上,在python3中,viewkeys是唯一仍然存在的行为,它已经被重命名为keysviewkeys方法实际上是python3行为的一个反向端口。


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

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

那么,iterkeys()itervalues()iteritems()呢?当您需要字典内容的一次性、恒定空间、延迟迭代器快照时(通过RuntimeError进行迭代),它们是一个合适的替代方法,可以告诉您字典是否在迭代时被修改过,而且它们对于向后兼容性非常重要。