python:使用’for’循环迭代字典

下面的代码让我有点困惑:

1
2
3
d = {'x': 1, 'y': 2, 'z': 3}
for key in d:
    print key, 'corresponds to', d[key]

我不明白的是key部分。Python如何识别它只需要从字典中读取键?在Python中key是一个特殊的单词吗?还是仅仅是一个变量?


key只是一个变量名。

1
for key in d:

将简单地循环字典中的键,而不是键和值。要遍历键和值,可以使用以下命令:

对于Python 2. x:

1
for key, value in d.iteritems():

对于Python 3. x:

1
for key, value in d.items():

要自己测试,请将单词key更改为poop

Python 3。x, iteritems()被简单地替换为items(),它返回由dict支持的类似集合的视图,类似于iteritems(),但更好。这在2.7中也可用作viewitems()

操作items()将同时适用于2和3,但是在2中,它将返回一个字典的(key, value)对列表,该列表不会反映在items()调用之后发生的对dict的更改。如果你想要2。x在3中的行为。x,可以调用list(d.items())


关键字并不是一个特殊的单词,而是字典实现了迭代器协议。您可以在您的类中这样做,例如,查看这个问题了解如何构建类迭代器。

对于字典,它是在C级实现的。详细信息可以在PEP 234中找到。特别是"字典迭代器"一节:

Dictionaries implement a tp_iter slot that returns an efficient
iterator that iterates over the keys of the dictionary. [...] This
means that we can write

1
for k in dict: ...

which is equivalent to, but much faster than

1
for k in dict.keys(): ...

as long as the restriction on modifications to the dictionary
(either by the loop or by another thread) are not violated.

Add methods to dictionaries that return different kinds of
iterators explicitly:

1
2
3
4
5
for key in dict.iterkeys(): ...

for value in dict.itervalues(): ...

for key, value in dict.iteritems(): ...

This means that for x in dict is shorthand for for x in
dict.iterkeys()
.

在python3中,不再支持dict.iterkeys()dict.itervalues()dict.iteritems()。而是使用dict.keys()dict.values()dict.items()


在一个dict上迭代没有特定的顺序遍历它的键,正如您在这里看到的:

编辑:(Python3.6中不再是这种情况,但注意它还不是保证行为)

1
2
3
4
5
>>> d = {'x': 1, 'y': 2, 'z': 3}
>>> list(d)
['y', 'x', 'z']
>>> d.keys()
['y', 'x', 'z']

对于你的例子,使用dict.items()是一个更好的主意:

1
2
>>> d.items()
[('y', 2), ('x', 1), ('z', 3)]

这将给出一个元组列表。当你像这样循环遍历它们时,每个元组都会自动解压缩成kv:

1
2
for k,v in d.items():
    print(k, 'corresponds to', v)

如果循环体只有几行代码,那么在遍历dict时使用kv作为变量名是很常见的。对于更复杂的循环,最好使用描述性更强的名称:

1
2
for letter, number in d.items():
    print(letter, 'corresponds to', number)

养成使用格式字符串的习惯是个好主意:

1
2
for letter, number in d.items():
    print('{0} corresponds to {1}'.format(letter, number))


key只是一个变量。

Python2.X:

1
2
3
d = {'x': 1, 'y': 2, 'z': 3}
for my_var in d:
    print my_var, 'corresponds to', d[my_var]

…或更好,

1
2
3
d = {'x': 1, 'y': 2, 'z': 3}
for the_key, the_value in d.iteritems():
    print the_key, 'corresponds to', the_value

Python3.X:

1
2
3
d = {'x': 1, 'y': 2, 'z': 3}
for the_key, the_value in d.items():
    print(the_key, 'corresponds to', the_value)

当您使用for .. in ..-语法遍历字典时,它总是遍历键(值可以使用dictionary[key]访问)。

要遍历键值对,请使用for k,v in s.iteritems()


这是一个非常常见的循环习语。in是一个操作符。有关何时使用for key in dict以及何时必须使用for key in dict.keys(),请参阅David Goodger的惯用Python文章。


你可以用这个:

1
2
for key,val in d.items():
    print key, 'is the key for ', val


我有一个用例,在这个用例中,我必须遍历dict来获得键值对,以及指示我所在位置的索引。我是这样做的:

1
2
3
d = {'x': 1, 'y': 2, 'z': 3}
for i, (key, value) in enumerate(d.items()):
   print(i, key, value)

注意,键值周围的括号很重要,没有括号,您将得到一个ValueError"not enough values to unpack"。


Iterating over dictionaries using 'for' loops

1
2
3
d = {'x': 1, 'y': 2, 'z': 3}
for key in d:
    ...

How does Python recognize that it needs only to read the key from the
dictionary? Is key a special word in Python? Or is it simply a
variable?

它不仅仅是for循环。这里的关键词是"迭代"。

字典是键到值的映射:

1
d = {'x': 1, 'y': 2, 'z': 3}

任何时候我们对它进行迭代,我们都要对键进行迭代。变量名key只是用来描述的,它非常适合这个目的。

这发生在列表理解中:

1
2
>>> [k for k in d]
['x', 'y', 'z']

当我们将字典传递给list(或任何其他集合类型对象)时,就会发生这种情况:

1
2
>>> list(d)
['x', 'y', 'z']

Python的迭代方法是,在需要的上下文中调用对象的__iter__方法(在本例中是dictionary),该方法返回一个迭代器(在本例中是keyiterator对象):

1
2
>>> d.__iter__()
<dict_keyiterator object at 0x7fb1747bee08>

我们不应该自己使用这些特殊的方法,而是使用各自的内置函数来调用它,iter:

1
2
3
>>> key_iterator = iter(d)
>>> key_iterator
<dict_keyiterator object at 0x7fb172fa9188>

迭代器有一个__next__方法,但是我们用内置函数next调用它:

1
2
3
4
5
6
7
8
9
10
>>> next(key_iterator)
'x'
>>> next(key_iterator)
'y'
>>> next(key_iterator)
'z'
>>> next(key_iterator)
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
StopIteration

当迭代器耗尽时,它会引发StopIteration。这就是Python知道如何退出for循环、列表理解、生成器表达式或任何其他迭代上下文的方法。一旦迭代器引发StopIteration,它总是会引发它——如果您想再次迭代,您需要一个新的迭代器。

1
2
3
4
5
>>> list(key_iterator)
[]
>>> new_key_iterator = iter(d)
>>> list(new_key_iterator)
['x', 'y', 'z']

回到字典

我们已经在许多上下文中看到了dict的迭代。我们所看到的是,任何时候我们对dict进行迭代,都会得到键。回到最初的例子:

1
2
d = {'x': 1, 'y': 2, 'z': 3}
for key in d:

如果我们改变变量名,仍然会得到键值。让我们试一试:

1
2
3
4
5
6
>>> for each_key in d:
...     print(each_key, '=>', d[each_key])
...
x => 1
y => 2
z => 3

如果我们想遍历这些值,我们需要使用dicts的.values方法,或者同时使用这两种方法,.items:

1
2
3
4
>>> list(d.values())
[1, 2, 3]
>>> list(d.items())
[('x', 1), ('y', 2), ('z', 3)]

在给出的例子中,像这样迭代项目会更有效:

1
2
for a_key, corresponding_value in d.items():
    print(a_key, corresponding_value)

但就学术目的而言,这个问题的例子很好。


无论如何,今天,python 2.6和2.7,以及3。x, in my box with items()很好用:

1
2
z = {0: 'a', 1: 'b'}
for k, v in z.items(): print(v, k)


您可以在GitHub上检查CPython的dicttype实现。这是实现dict迭代器的方法的签名:

1
2
_PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey,
             PyObject **pvalue, Py_hash_t *phash)

CPython dictobject.c


要遍历键,使用my_dict.keys()会慢一些,但效果更好。如果你想这样做:

1
2
for key in my_dict:
    my_dict[key+"-1"] = my_dict[key]-1

它将创建一个运行时错误,因为您在程序运行时更改键。如果您绝对想要减少时间,请使用for key in my_dict方法,但是有人警告过您;)。


my_dict中的For键实际上等于my_dict.keys()中的For键。如果你想要得到dict的值,你可以尝试两种方法。

一:

1
2
for value in my_dict.values():
    print(value)

二:

1
2
for key in my_dict:
    print(my_dict[key])