Перебора словарей, используя 'для' петли

Я немного озадачен следующим кодом:

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

чего я не понимаю-это key часть. Как Python распознает, что ему нужно только прочитать ключ из словаря? Is key специальное слово в Python? Или это просто переменная?

11 ответов


key - это просто имя переменной.

for key in d:

будет просто перебирать ключи в словаре, а не ключи и значения. Для перебора как ключа, так и значения вы можете использовать следующее:

Для Python 2.x:

for key, value in d.iteritems():

Для Python 3.x:

for key, value in d.items():

чтобы проверить для себя, измените слово key to poop.

Для Python 3.x,iteritems() был заменен на просто items(), который возвращает set-like вид поддерживается дикт, как iteritems() но даже лучше. Это также доступно в 2.7 as viewitems().

операция items() будет работать как для 2, так и для 3, но в 2 он вернет список словаря (key, value) пары, которые не будут отражать изменения в dict, которые происходят после items() звонок. Если вы хотите 2.X поведение в 3.х, вы можете позвонить list(d.items()).


это не то, что ключ является специальным словом, но что словари реализуют протокол итератора. Вы можете сделать это в своем классе, например, см. этот вопрос для создания итераторов классов.

в случае словарей, он реализован на уровне C. Подробности доступны в PEP 234. В частности, раздел под названием "итераторы словаря":

  • словари реализуют слот tp_iter, который возвращает эффективное iterator, который выполняет итерации по ключам словаря. [...] Этот значит, мы можем писать

    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 dict - это сокращение для for x in dict.iterkeys().


повторение над dict перебирает свои ключи в определенном порядке, как вы можете видеть здесь:

Edit: (это не в Питон3.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)]

это дает вам список кортежей. Когда вы петляете над ними, каждый кортеж распаковывается в k и v автоматически:

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

используя k и v как имена переменных при циклическом замыкании на dict довольно распространен, если тело цикла составляет всего несколько строк. Для более сложных циклов может быть хорошей идеей использовать более описательные имена:

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

на Питон3.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 ..-синтаксис, он всегда перебирает ключи (значения можно с помощью dictionary[key]).

для перебора пар ключ-значение, используйте for k,v in s.iteritems().


Это очень распространенная идиома цикла. in - Это оператор. Для того, когда использовать for key in dict и когда это должно быть for key in dict.keys() посмотреть Дэвид Гуджер это.


вы можете использовать это:

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

У меня есть прецедент, когда я должен перебирать dict, чтобы получить ключ, пару значений, а также индекс, указывающий, где я нахожусь. Вот как я это делаю:--2-->

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 распознает, что ему нужно только прочитать ключ из словарь? Является ли key специальным словом в 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__ метод объекта (в данном случае словаря), который возвращает итератор (в данном случае-кейитератор объект):

>>> 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)

но для академических целей, пример вопроса-просто отлично.


Вы можете проверить реализацию с CPython это dicttype на GitHub. Это подпись метода, реализующего итератор 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 путь, но вы были предупреждены ;).