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

Mic*_*ber 25 python python-2.7

在Python 2.7中,字典既有iterkeys方法又有viewkeys方法(以及值和项的类似对),提供两种不同的方式来懒惰地迭代字典的键.该viewkeys方法提供的主要特征iterkeys,具有iter(d.viewkeys())实际上等效于d.iterkeys().此外,返回的对象viewkeys具有方便的类似集的功能.因此,有充分的理由看好viewkeysiterkeys.

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

Gar*_*tty 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])
Run Code Online (Sandbox Code Playgroud)

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

>>> 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])
Run Code Online (Sandbox Code Playgroud)

值得注意的是,您只能迭代一次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])
Run Code Online (Sandbox Code Playgroud)

  • 重要的是要意识到迭代器不会为字典中的任何更改引发`RuntimeError`; 仅适用于尺寸变化.`del test [3]; 迭代器创建和迭代之间的test [5] = 6`不会使它失效,也不会`test [3] = 91`.因此它很危险. (3认同)
  • 这一切都是正确的,但实际上并没有解决这个问题 - OP知道`viewkeys`的作用,并特别询问是否存在假装`iterkeys`不存在的任何缺点. (2认同)
  • @lvc它解释了差异,这可以被认为是``iterkeys()``的积极因素 - 例如,如果你不希望它更新的可能性,使用``iterkeys()``可能更合适(虽然可以用``viewkeys()``创建相同的功能.我不是说这是一个强有力的理由,但它几乎是唯一的理由. (2认同)
  • 注意:2.7 的文档页面说“在字典中添加或删除条目时迭代视图可能会引发 RuntimeError 或无法遍历所有条目。” 我读到这意味着传递 dictview 是安全的,并且稍后开始迭代(在进行更改之后),但是一旦开始迭代,就无法安全地更改字典。如果没有意识到这一警告,人们可能会认为视图方法提供了一种在迭代字典时修改字典的方法。不安全(在 2.7 中)。相反,在迭代时列出“要删除的键”,然后稍后删除这些键 (2认同)

Chr*_*gan 15

功能方面,正如您所观察到的,观点更好.兼容性方面,它们更糟糕.

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

>>> from timeit import timeit
Run Code Online (Sandbox Code Playgroud)

处理空字典:

>>> 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
Run Code Online (Sandbox Code Playgroud)

构造视图稍微昂贵一些,但是消耗视图的速度明显快于迭代器(速度快一倍).

处理千元字典:

>>> 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
Run Code Online (Sandbox Code Playgroud)

结果相同,但不太明显; 构建视图的成本略高,但消耗它的速度肯定更快(快15%).

对于公平的比较list(dict.viewkeys())list(dict.iterkeys()),dict.keys()是distinctlyfaster:

>>> timeit(lambda: emptydict.keys())
0.2385849952697754
>>> timeit(lambda: fulldict.keys())
7.842105150222778
Run Code Online (Sandbox Code Playgroud)

总结:这是一种权衡; 更好的功能(你将很少使用)和性能(这只会非常罕见足以显著担心你,如果你关心这样的表现的问题,你可能已经在需要的区域与numpy的/ SciPy的工作)与更好的兼容性和肌肉记忆使用.

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


lvc*_*lvc 11

不,没有任何优势可以iterkeys结束viewkeys,就像它们中的任何一个都没有优势keys一样.iterkeys只是为了兼容后兼容.实际上,在Python 3中,viewkeys唯一仍然存在的行为,并且它已被重命名为keys- 该viewkeys方法实际上是Python 3行为的后端.

  • @SystemParadox这个问题显然没有确切地问到差异是什么 - OP特别询问使用`iter*`而不是`view*'是否有任何优势,并且*已经列出了*在另一个方向上的优势. (7认同)
  • 这并不能解释任何差异 (5认同)

Ósc*_*pez 8

正如其名字(和文档)所表明,viewkeys(),viewvalues()viewitems()方法都返回一个视图在字典中的意思,如果词典的变化,因此不认为当前元件; 意见 懒散.在一般情况下,视图是类似于集合的,并且如果值是可哈希的,则项目视图仅设置为类似.

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

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