Перебор словарей с использованием циклов for

2385

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

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

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

Теги:
dictionary
python-2.7

12 ответов

4081
Лучший ответ

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

for key in d:

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

Для Python 2.x:

for key, value in d.iteritems():

Для Python 3.x:

for key, value in d.items():

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

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

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

  • 94
    Добавление пропущенной причины отказа от доступа к значению, подобному следующему: d [ключ] внутри цикла for приводит к повторному хешированию ключа (для получения значения). Когда словарь большой, этот дополнительный хеш добавит к общему времени. Это обсуждается в техническом докладе Рэймонда Хеттингера youtube.com/watch?v=anrOzOapJ2E
  • 10
    Возможно, имеет смысл упомянуть, что элементы будут повторяться в непредсказуемом порядке, и для их стабилизации необходима sorted .
Показать ещё 6 комментариев
341

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

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

  • 60
    В python3 dict.iterkeys (), dict.itervalues () и dict.iteritems () больше не поддерживаются. Вместо этого используйте dict.keys (), dict.values () и dict.items ().
169

Итерация по 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)]

Это дает вам список кортежей. Когда вы перебираете их так, каждый кортеж распаковывается в 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))
  • 4
    Из примечаний к выпуску Python 3.7: «Природа сохранения порядка вставки объектов dict теперь является официальной частью спецификации языка Python».
55

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

Когда вы повторяете словари с помощью for .. in .. -syntax, он всегда выполняет итерацию по клавишам (значения доступны с помощью dictionary[key]).

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

  • 32
    Обратите внимание, что для Python 3 это items() вместо iteritems()
22

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

10

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

for key,val in d.items():
    print key, 'is the key for ', val
  • 5
    Это немного старый пост
  • 1
    @Sadi Это больше не правда?
8

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

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

Обратите внимание, что круглые скобки вокруг ключа, значение важно, без круглых скобок вы получаете значение ValueError "Недостаточно значений для распаковки".

6

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

>>> 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']

Возврат к dicts

Мы видели, как во многих контекстах итерации повторялись. То, что мы видели, это то, что в любой момент, когда мы перебираем диктофон, мы получаем ключи. Вернемся к исходному примеру:

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 dicts или для обоих вместе .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)

Но для академических целей пример вопроса просто замечательный.

4

Вы можете проверить реализацию dicttype CPython на GitHub. Это подпись метода, который реализует итератор dict:

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

CPython dictobject.c

1

Чтобы перебирать клавиши, это медленнее, но лучше использовать my_dict.keys(). Если вы попытались сделать что-то вроде этого:

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

он создаст ошибку времени выполнения, потому что вы меняете ключи во время работы программы. Если вы абсолютно настроены на сокращение времени, используйте способ for key in my_dict, но вы были предупреждены;).

0

Python 2

Диктонарии - это очень важный tpo Python, который также очень прост в использовании. Для повторения каждой клавиши словаря вы просто используете "для k в d" или "для ключа в d" или любую переменную вместо k или ключа, как в моих примерах. Это потому, что по умолчанию вы можете перебирать ключи словаря именно так. для доступа к значениям ключей, которые вы нам только выбрали d [k] или d [key] или d [nameofvariable], в зависимости от переменной, которую вы использовали в цикле, для итерации ключей.

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

Python 3.6

вы также можете сделать что-то вроде этого:

d = {'x': 1, 'y': 2, 'z': 3} 
for k,v in d.items():
    print(k,":",v)

Выход

x : 1
y : 2
z : 3

Ещё вопросы

Сообщество Overcoder
Наверх
Меню