在Python 3中遍历字典的items()、values()和keys()

48 投票
1 回答
102757 浏览
提问于 2025-04-16 03:34

如果我理解得没错,在Python 2中,iter(d.keys())d.iterkeys()是一样的。但在Python 3中,d.keys()变成了一个“视图”,这介于列表和迭代器之间。那么,视图和迭代器有什么区别呢?

换句话说,在Python 3中,

for k in d.keys()
    f(k)

for k in iter(d.keys())
    f(k)

有什么不同呢?

另外,这些区别在简单的for循环中会有什么表现(如果有的话)?

1 个回答

72

我不确定这是否能完全回答你的问题,但希望能帮你理解Python 2和3在这方面的区别。

在Python 2中,iter(d.keys())d.iterkeys()虽然表现得一样,但其实并不完全相同。第一个是keys()会返回字典键的一个列表副本,然后iter会在这个列表上创建一个迭代器。而第二个则不会创建完整的键列表副本。

在Python 3中,d.keys()返回的视图对象是可迭代的(也就是说,可以从中创建一个迭代器),所以当你写for k in d.keys()时,Python会自动为你创建这个迭代器。因此,你的两个例子会表现得一样。

返回类型的变化很重要,因为Python 3的视图对象是动态的。也就是说,如果我们写ks = d.keys(),然后再往d里添加内容,ks会反映出这些变化。在Python 2中,keys()返回的是当前字典中所有键的一个列表。对比一下:

Python 3

>>> d = { "first" : 1, "second" : 2 }
>>> ks = d.keys()
>>> ks
dict_keys(['second', 'first'])
>>> d["third"] = 3
>>> ks
dict_keys(['second', 'third', 'first'])

Python 2.x

>>> d = { "first" : 1, "second" : 2 }
>>> ks = d.keys()
>>> ks
['second', 'first']
>>> d["third"] = 3
>>> ks
['second', 'first']

由于Python 3的keys()返回的是动态对象,所以Python 3不需要单独的iterkeys方法。

进一步说明

在Python 3中,keys()返回一个dict_keys对象,但如果我们在for循环中使用它,比如for k in d.keys(),那么会隐式地创建一个迭代器。所以for k in d.keys()for k in iter(d.keys())之间的区别在于迭代器的创建是隐式的还是显式的。

另外一个区别是,虽然它们都是动态的,但如果我们创建了一个显式的迭代器,它只能使用一次,而视图可以根据需要重复使用。例如:

>>> ks = d.keys()
>>> 'first' in ks
True
>>> 'second' in ks
True
>>> i = iter(d.keys())
>>> 'first' in i
True
>>> 'second' in i
False             # because we've already reached the end of the iterator

另外,如果我们创建了一个显式的迭代器,然后修改了字典,这个迭代器就会失效:

>>> i2 = iter(d.keys())
>>> d['fourth'] = 4
>>> for k in i2: print(k)
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration

在Python 2中,由于keys的现有行为,需要一个单独的方法来提供一种不复制键列表的迭代方式,同时保持向后兼容。因此有了iterkeys()

撰写回答