在Python 2.7中,字典同时具有iterkeys
方法和viewkeys
方法(以及值和项的类似对),提供了两种不同的方式来懒惰地迭代字典的键。 viewkeys
方法提供iterkeys
的主要功能,iter(d.viewkeys())
实际上等同于d.iterkeys()
。此外,返回的对象viewkeys
具有方便的类似集的功能。因此有充分的理由支持viewkeys
而不是iterkeys
。
另一个方向呢?除了与早期版本的Python兼容之外,iterkeys
有哪些方法比viewkeys
更受欢迎?总是使用viewkeys
会有什么损失吗?
答案 0 :(得分:21)
字典视图会像字典一样更新,而迭代器不一定会这样做。
这意味着如果您使用视图,更改字典,然后再次使用视图,视图将更改以反映字典的新状态。
它们提供了字典条目的动态视图,这意味着当字典更改时,视图会反映这些更改。 Source
示例:
>>> 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])
同样值得注意的是,你只能在一次赎罪主义者身上进行迭代:
>>> 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])
答案 1 :(得分: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())
和list(dict.iterkeys())
进行公平比较,dict.keys()
明显更快:
>>> timeit(lambda: emptydict.keys())
0.2385849952697754
>>> timeit(lambda: fulldict.keys())
7.842105150222778
摘要:这是一种权衡;更好的功能(你很少会使用)和性能(只有非常很少会让你担心 - 如果你关心这些性能问题,你可能已经在需要使用numpy / scipy)与更好的兼容性和肌肉记忆使用。
就个人而言,除非已经依赖于2.7-only功能,或者除非我绝对控制运行时环境,否则我会避免使用Python 2代码中的字典视图。即使在这些情况下,我的手指仍然想要输入iter
而不是view
,所以我让他们!
答案 2 :(得分:10)
不,iterkeys
优于viewkeys
没有优势,就像keys
对其中任何一个都没有优势一样。 iterkeys
仅用于兼容后兼容。实际上,在Python 3中,viewkeys
是唯一仍然存在的行为,并且它已被重命名为keys
- viewkeys
方法实际上是Python 3行为的后端。
答案 3 :(得分:7)
正如名称(以及documentation)所示,viewkeys()
,viewvalues()
和viewitems()
方法会返回当前元素的视图字典意味着如果字典改变,视图也会改变;视图 lazy。在一般情况下, keys 视图是类似于设置的,并且 item 视图仅在值可以清除时才设置为类似。
在哪些情况下使用标准方法keys()
,values()
和items()
会更好?你提到了一个非常重要的问题:向后兼容性。此外,当您需要拥有所有键,值或项(不是类似集合,而不是迭代器)的简单列表时,需要在不修改原始字典的情况下修改返回的列表以及何时需要快照字典中的字典键,值或项目,与字典上的任何后验修改无关。
那么iterkeys()
,itervalues()
和iteritems()
呢?当你需要一个字典内容的一次性,恒定空间,懒惰的迭代器快照时,它们是一个合适的选择,它会告诉你字典是否在迭代时被修改(通过RuntimeError
),它们也是对于向后兼容性非常重要。