Python 3.0 - dict 方法返回视图 - 为啥?
Posted
技术标签:
【中文标题】Python 3.0 - dict 方法返回视图 - 为啥?【英文标题】:Python 3.0 - dict methods return views - why?Python 3.0 - dict 方法返回视图 - 为什么? 【发布时间】:2010-09-25 08:19:03 【问题描述】:dict 方法 dict.keys(), dict.items() 和 dict.values() 返回“视图” 而不是列表。 http://docs.python.org/dev/3.0/whatsnew//3.0.html
首先,视图与迭代器有何不同?其次,这种变化有什么好处?仅仅是出于性能原因吗?
这对我来说似乎并不直观,即,我要一份东西的清单(把你所有的钥匙给我),然后我又得到了别的东西。这会让人们感到困惑吗?
【问题讨论】:
这是关于 *** 的一个很好的答案:***.com/questions/8957750/… 网址好像失效了。 【参考方案1】:您实际上得到了一份清单。它不是内部列表的副本,而是类似于列表但仅代表内部状态的东西。
这与它在 Java(可能还有许多其他语言/环境)中实现的方式相同。
主要原因是对于许多用例而言,返回完全分离的列表是不必要且浪费的。这将需要复制整个内容(可能很多,也可能不多)。
如果您只是想遍历键,则无需创建新列表。如果您确实需要将其作为单独的列表(作为副本),那么您可以轻松地从视图中创建该列表。
【讨论】:
【参考方案2】:Joachim Sauer 的回答很好地解释了为什么不返回 list
。但这留下了为什么这些函数不会返回迭代器的问题,就像iteritems
等在 Python 2 中所做的那样。
迭代器比容器更严格。例如,一个迭代器不允许超过一次传递;如果你尝试第二遍,你会发现它是空的。因此,容器支持elem in cont
等操作,但迭代器不支持:一旦检查元素是否在迭代器“内”,迭代器就会被销毁!
另一方面,获取容器通常需要制作副本,例如从字典的键中创建一个列表。
view
对象具有两全其美的优点:它充当容器,但不会复制字典!实际上,它是一种通过链接到底层字典来工作的虚拟只读容器。我不知道它是否在标准 Python 的其他任何地方都可以看到。
编辑:
@AntonyHatchkins:它不返回生成器函数的原因是它不允许快速的in
操作。是的,in
适用于生成器函数(当您调用它们时)。也就是说,您可以这样做:
def f():
for i in range(10):
yield i
5 in f() # True
但是根据in
的定义,如果右边是生成器,python会遍历生成器的所有n
项——导致O(n)
时间复杂度。您对此无能为力,因为这是任意生成器唯一有意义的行为。
另一方面,在字典视图的情况下,您可以以任何您喜欢的方式实现in
,因为您对自己管理的数据了解得更多。事实上in
是使用哈希表以O(1)
复杂性实现的。你可以通过运行来检查它
>>> d = dict(zip(range(50000000), range(50000000)))
>>> 49999999 in d
True
>>> 49999999 in iter(d) # kinda how generator function would work
True
>>>
并注意到第一个 in
与第二个 in
相比有多快。
【讨论】:
然后是另一个问题,为什么不返回生成器函数。它们是多通道实体(因此也支持elem in cont
操作)并且不会占用太多内存。
@AntonyHatchkins 编辑了答案以解释原因
谢谢,从那时起我自己就学会了,但它可能对其他人也有用。【参考方案3】:
正如在相关问题中已经提到的那样,视图有 len()
方法,这是迭代器所缺少的(但列表有它)。
返回视图而不是列表的另一个好处是,至少对于键,它在 O(1) 操作中优化了成员资格测试,而不是对列表(或迭代器)进行 O(N)。
【讨论】:
以上是关于Python 3.0 - dict 方法返回视图 - 为啥?的主要内容,如果未能解决你的问题,请参考以下文章