使用 “for” 循环遍历字典

以下代码使我有些困惑:

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

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

答案

key只是一个变量名。

for key in d:

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

对于 Python 3.x:

for key, value in d.items():

对于 Python 2.x:

for key, value in d.iteritems():

要进行自我测试,请将单词key更改为poop

在 Python 3.x 中, iteritems()替换为简单的items() ,它返回了由 dict 支持的类似 set 的视图,就像iteritems()但效果更好。在 2.7 中也可以通过viewitems()

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

并不是说键是一个特殊的词,而是字典实现了迭代器协议。您可以在您的类中执行此操作,例如,有关如何构建类迭代器的信息,请参见此问题

对于字典,它是在 C 级别实现的。详细信息在PEP 234中可用。特别是标题为 “字典迭代器” 的部分:

  • 字典实现了一个 tp_iter 插槽,该插槽返回一个有效的迭代器,该迭代器对字典的键进行迭代。 [...] 这意味着我们可以写

    for k in dict: ...

    相当于,但是比

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

    只要不违反对字典修改的限制(无论是通过循环还是通过其他线程)。

  • 将方法添加到字典中,以显式返回不同种类的迭代器:

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

    这意味着for x in dictfor x in dict.iterkeys()简写。

在 Python 3 中,不再支持dict.iterkeys()dict.itervalues()dict.iteritems() 。使用dict.keys() dict.values()dict.items()来代替。

如上所示,对dict遍历将以其键无特定顺序进行遍历。

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

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

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

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

这为您提供了一个元组列表。当您像这样循环遍历它们时,每个元组会自动解包为kv

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

如果循环的主体只有几行,则在遍历dict时使用kv作为变量名非常普遍。对于更复杂的循环,最好使用更具描述性的名称:

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

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

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

key只是一个变量。

对于Python2.X

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

... 或更好,

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

对于Python3.X

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

for .. in .. -syntax 中使用for .. in ..字典中进行迭代时,它总是在键上进行迭代(可以使用dictionary[key]来访问值)。

要遍历键值对,在 Python 2 for k,v in s.iteritems()for k,v in s.items() ,在 Python 3 for k,v in s.items()

这是一个非常常见的循环习惯用法。 in是一个运算符。有关何时使用for key in dict以及何时必须使用for key in dict.keys()请参阅David Goodger 的 Idiomatic Python 文章(归档副本)

我有一个用例,我必须遍历字典以获取键,值对以及指示我在哪里的索引。这是我的方法:

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

请注意,键值周围的括号很重要,如果没有括号,则会出现 ValueError“没有足够的值要解压”。

使用 “for” 循环遍历字典

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

Python 如何识别只需要从字典中读取密钥?关键字在 Python 中是一个特殊的词吗?还是仅仅是一个变量?

这不仅是for循环。这里重要的词是 “迭代”。

字典是键到值的映射:

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

每当我们遍历它时,我们都会遍历键。变量名key仅是描述性的,非常适合此目的。

这发生在列表理解中:

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

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

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

Python 进行迭代的方式是,在需要的上下文中,它调用对象的__iter__方法(在这种情况下为字典),该方法返回迭代器(在这种情况下为 keyiterator 对象):

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

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

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

迭代器具有__next__方法 - 但是我们使用内置函数next调用它:

>>> 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 ,它将始终引发它 - 如果要再次迭代,则需要一个新的迭代器。

>>> list(key_iterator)
[]
>>> new_key_iterator = iter(d)
>>> list(new_key_iterator)
['x', 'y', 'z']

返回字典

我们已经看到在许多情况下都会反复进行命令。我们看到的是,每当我们迭代一个字典时,我们都会得到密钥。回到原始示例:

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

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

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

如果要遍历值,则需要使用字典的.values方法,或者同时使用.items

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

在给定的示例中,迭代如下所示的项将更加有效:

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

但是出于学术目的,这个问题的例子很好。

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

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

CPython 的 dictobject.c

要遍历键,使用my_dict.keys()较慢,但更好。如果您尝试执行以下操作:

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

这将导致运行时错误,因为在程序运行时更改了密钥。如果您绝对希望减少时间,请for key in my_dict方式使用for key in my_dict ,但已被警告;)。