[英]What are dictionary view objects?
在python 2.7中,我们获得了可用的字典视图方法 。
现在,我知道以下的利弊:
dict.items()
(和values
, keys
):返回一个列表,这样你就可以实际存储结果,和 dict.iteritems()
(等):返回一个生成器,因此你可以迭代生成逐个生成的每个值。 什么是dict.viewitems()
(等)? 他们有什么好处? 它是如何工作的? 什么是观点?
我读到视图总是反映字典中的变化。 但是从性能和内存的角度来看它是如何表现的呢? 有什么利弊?
字典视图基本上就是他们的名字所说的: 视图就像一个关于字典的键和值(或项)的窗口 。 以下是Python 3 官方文档的摘录:
>>> 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()
。)
此示例显示了视图的动态特性 :键视图不是给定时间点的键的副本,而是一个向您显示键的简单窗口; 如果它们被改变了,那么你在窗口看到的东西也会发生变化。 在某些情况下,此功能非常有用(例如,可以使用程序的多个部分中的键的视图,而不是每次需要时重新计算当前的键列表) - 注意如果修改了字典键迭代视图时,迭代器的行为方式没有明确定义,这可能导致错误 。
一个优点是,例如, 查看密钥仅使用少量固定数量的内存,并且需要少量且固定数量的处理器时间 ,因为没有创建密钥列表(另一方面,Python 2,通常不必要地创建一个新的列表,如Rajendran T引用的那样,它占用的内存和时间与列表的长度成比例)。 要继续窗口类比,如果你想看到墙后面的风景,你只需在其中打开一个开口(你建立一个窗口); 将密钥复制到列表中将相应于在墙上绘制景观的副本 - 复制需要时间,空间,并且不会自行更新。
总而言之,视图只是...字典上的视图(窗口),即使在更改后也会显示字典的内容。 它们提供的功能与列表的功能不同:键列表包含给定时间点的字典键副本 ,而视图是动态的,获取速度更快,因为它不需要复制任何数据(键或值)以便创建。
正如您所提到的, dict.items()
返回字典的(键,值)对列表的副本,这是浪费的, dict.iteritems()
返回字典(键,值)对上的迭代器。
现在采用以下示例来查看dict的interator和dict的视图之间的区别
>>> 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
而视图只是向您显示字典中的内容。 它不关心它是否改变:
>>> 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()
会抛出错误。
视图方法返回一个列表(不是列表的副本,与.keys()
.items()
和.values()
),因此它更轻量级,但反映了字典的当前内容。
从Python 3.0 - dict方法返回视图 - 为什么?
主要原因是,对于许多用例而言,返回完全独立的列表是不必要和浪费的。 它需要复制整个内容(可能或许多不是很多)。
如果您只想迭代密钥,则无需创建新列表。 如果您确实需要它作为单独的列表(作为副本),那么您可以从视图中轻松创建该列表。
只是阅读文档,我得到了这样的印象:
所以我想关键的用例是如果你保持一个字典并反复迭代它的键/项/值,并在两者之间进行修改。 您可以只使用视图, for k, v in mydict.iteritems():
转换for k, v in myview:
转换for k, v in myview:
. 但如果你只是在字典上迭代一次,我认为iter-版本仍然更可取。
通过视图,您可以访问底层数据结构,而无需复制它。 除了是动态的,而不是创造一个名单,他们最有用的用途之一是in
测试。 假设您要检查某个值是否在dict中(无论是键还是值)。
选项一是使用dict.keys()
创建一个键列表,这可以工作,但显然会消耗更多的内存。 如果dict非常大? 那将是浪费。
使用views
您可以迭代实际的数据结构,而无需中间列表。
我们来看一些例子。 我有一个带有1000个随机字符串和数字键的字典, k
是我想要查找的键
large_d = { .. 'NBBDC': '0RMLH', 'E01AS': 'UAZIQ', 'G0SSL': '6117Y', 'LYBZ7': 'VC8JQ' .. }
>>> len(large_d)
1000
# this is one option; It creates the keys() list every time, it's here just for the example
timeit.timeit('k in large_d.keys()', setup='from __main__ import large_d, k', number=1000000)
13.748743600954867
# now let's create the list first; only then check for containment
>>> list_keys = large_d.keys()
>>> timeit.timeit('k in list_keys', setup='from __main__ import large_d, k, list_keys', number=1000000)
8.874809793833492
# this saves us ~5 seconds. Great!
# let's try the views now
>>> timeit.timeit('k in large_d.viewkeys()', setup='from __main__ import large_d, k', number=1000000)
0.08828549011070663
# How about saving another 8.5 seconds?
正如您所看到的,迭代view
对象可以极大地提升性能,同时减少内存开销。 当您需要执行Set
like operations时,您应该使用它们。
注意 :我正在运行Python 2.7
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.