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

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

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

3748
TopChef 21 Июл 2010 в 02:27

10 ответов

Лучший ответ

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, как iteritems(), но даже лучше. Это также доступно в 2.7 как viewitems().

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

5213
Jason 3 Янв 2020 в 05:46

Итерации по 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))
199
nescius 31 Окт 2017 в 15:12

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)
81
ssoler 15 Июн 2018 в 10:51

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

30
Georgy 24 Май 2019 в 13:52

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

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

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

17
jdhao 2 Июн 2017 в 15:37

Перебор словарей с использованием циклов 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

Если мы хотим перебрать значения, нам нужно использовать метод dicts .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)

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

15
Aaron Hall 21 Июн 2017 в 02:51

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

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

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

3
Neil Chowdhury o_O 31 Дек 2015 в 18:39

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

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

CPython dictobject.c

7
Peter Mortensen 19 Май 2018 в 18:38

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

Для итерации по парам ключ-значение в Python 2 используйте for k,v in s.iteritems(), а в Python 3 for k,v in s.items().

59
Georgy 24 Май 2019 в 13:41

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

В случае словарей это реализовано на уровне C. Подробности доступны в PEP 234. В частности, раздел под названием «Словарь итераторов»:

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

      для k в dict: ...  

    что эквивалентно, но намного быстрее чем

      для k в dict.keys (): ...  

    до тех пор, пока ограничение на изменения в словаре (либо циклом, либо другим потоком) не нарушаются.

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

      для ключа в dict.iterkeys (): ... для значения в dict.itervalues (): ... для ключа значение в dict.iteritems (): ...  

    Это означает, что for x in dict является сокращением для для x в dict.iterkeys ( ) .

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

418
jpp 30 Ноя 2018 в 00:11