什么是字典视图对象?

2024-05-16 19:42:59 发布

您现在位置:Python中文网/ 问答频道 /正文

在Python2.7中,我们得到了可用的dictionary view methods

现在,我知道以下的利弊:

  • dict.items()(和valueskeys):返回一个列表,因此您可以实际存储结果,并且
  • dict.iteritems()(等等):返回一个生成器,因此您可以逐个迭代生成的每个值。

dict.viewitems()(等等)是干什么的?他们的好处是什么?它是如何工作的?究竟什么是风景?

我读到这一观点总是反映出词典的变化。但从性能和内存的角度来看,它是如何表现的呢?赞成和反对的是什么?


Tags: view列表dictionaryitemskeys性能dict词典
3条回答

正如您所提到的,dict.items()返回字典的(键,值)对列表的副本,这是浪费的,dict.iteritems()返回字典(键,值)对上的迭代器。

现在以下面的例子来看看dict的interator和dict的view之间的区别

>>> d = {"x":5, "y":3}
>>> iter = d.iteritems()
>>> del d["x"]
>>> for i in iter: print i
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration

而一个视图只是简单地向您显示dict中的内容,而不管它是否发生了变化:

>>> d = {"x":5, "y":3}
>>> v = d.viewitems()
>>> v
dict_items([('y', 3), ('x', 5)])
>>> del d["x"]
>>> v
dict_items([('y', 3)])

视图只是字典现在的样子。删除条目后,.items()将过期,.iteritems()将引发错误。

字典视图本质上就是它们的名称:视图就像一个关于字典键和值(或项)的窗口。以下是Python 3的official documentation摘录:

>>> dishes = {'eggs': 2, 'sausage': 1, 'bacon': 1, 'spam': 500}
>>> keys = dishes.keys()
>>> values = dishes.values()

>>> # view objects are dynamic and reflect dict changes
>>> del dishes['eggs']
>>> keys  # No eggs anymore!
dict_keys(['sausage', 'bacon', 'spam'])

>>> values  # No eggs value (2) anymore!
dict_values([1, 1, 500])

(相当于Python 2的代码使用dishes.viewkeys()dishes.viewvalues()。)

此示例显示视图的动态特性:keys视图不是给定时间点的键的副本,而是一个显示键的简单窗口;如果键被更改,则通过窗口看到的内容也会更改。此功能在某些情况下可能很有用(例如,可以在程序的多个部分中使用键的视图,而不是在每次需要时重新计算当前键列表)-请注意,如果在视图上迭代时修改了字典键,则迭代器的行为方式没有很好地定义,这可能lead to errors

一个优点是,查看这些键时,只使用少量的固定内存,并且需要少量的固定处理器时间,因为不需要创建键列表(另一方面,Python 2常常不必要地创建一个新列表,如Rajendran T所引述,它需要与列表长度成比例的内存和时间)。要继续进行窗口类比,如果您想看到墙后的景观,只需在其中打开一个孔(您可以构建一个窗口);将键复制到列表中,将对应于在墙上绘制景观的副本,副本需要时间、空间,并且不会自我更新。

总而言之,视图只是字典上的…视图(窗口),即使字典发生更改,它也会显示字典的内容。它们提供了不同于列表的特性:键列表在给定的时间点包含字典键的copy,而视图是动态的,获取速度更快,因为它不必复制任何数据(键或值)就可以创建。

仅仅从阅读文档中我就得到了这样的印象:

  1. 视图是“伪集合”,因为它们不支持索引,所以您可以使用它们来测试成员资格并对其进行迭代(因为键是散列的且唯一的,所以键和项视图更像“集合”,因为它们不包含重复项)。
  2. 您可以存储它们并多次使用,就像列表版本一样。
  3. 因为它们反映了底层字典,字典中的任何更改都将更改视图,并且几乎肯定会更改迭代的顺序。所以与列表版本不同,它们并不“稳定”。
  4. 因为它们反映了底层字典,所以几乎可以肯定它们是小代理对象;复制键/值/项需要以某种方式查看原始字典,并在发生更改时多次复制,这将是一个荒谬的实现。所以我希望内存开销很小,但是访问比直接访问字典要慢一点。

所以我猜关键的用例是,如果你保存一个字典,并在其键/项/值之间反复迭代,并在其间进行修改。您可以改为使用视图,将for k, v in mydict.iteritems():转换为for k, v in myview:。但是,如果你只是在字典上重复一次,我认为iter版本还是比较好的。

相关问题 更多 >