dict 方法 dict.keys()、dict.items() 和 dict.values() 返回“视图”而不是列表。 http://docs.python.org/dev/3.0/whatsnew//3.0.html
首先,视图与迭代器有何不同?其次,这种变化有什么好处?仅仅是出于性能原因吗?
这对我来说似乎并不直观,即,我要一份东西清单(把你所有的钥匙给我),然后我又得到了别的东西。这会让人们感到困惑吗?
dict 方法 dict.keys()、dict.items() 和 dict.values() 返回“视图”而不是列表。 http://docs.python.org/dev/3.0/whatsnew//3.0.html
首先,视图与迭代器有何不同?其次,这种变化有什么好处?仅仅是出于性能原因吗?
这对我来说似乎并不直观,即,我要一份东西清单(把你所有的钥匙给我),然后我又得到了别的东西。这会让人们感到困惑吗?
你实际上得到了一份清单。它只是不是内部列表的副本,而是充当列表但仅代表内部状态的东西。
这与它在 Java 中实现的方式相同(可能还有许多其他语言/环境)。
主要原因是对于许多用例来说,返回一个完全分离的列表是不必要且浪费的。它需要复制整个内容(可能很多,也可能不多)。
如果您只是想遍历键,则无需创建新列表。如果您确实需要它作为单独的列表(作为副本),那么您可以轻松地从视图中创建该列表。
Joachim Sauer 的回答很好地解释了为什么list
不返回 a 。但这留下了一个问题,为什么这些函数不会返回迭代器,就像iteritems
Python 2 中的 etc. 那样。
迭代器比容器更具限制性。例如,一个迭代器不允许超过一次传递;如果你尝试第二遍,你会发现它是空的。因此,容器支持诸如此类的操作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
。
正如在相关问题中已经提到的那样,视图具有len()
迭代器缺少的方法(但列表有)。
返回视图而不是列表的另一个好处是,至少对于键而言,它在 O(1) 操作中优化了成员资格测试,而不是列表(或迭代器)的 O(N)。