Перебор словарей с использованием циклов for - PullRequest
2755 голосов
/ 21 июля 2010

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

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

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

Ответы [ 10 ]

4857 голосов
/ 21 июля 2010

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

391 голосов
/ 21 июля 2010

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

В случае словарей, это реализовано на уровне 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().

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

186 голосов
/ 21 июля 2010

Итерация по 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))
72 голосов
/ 21 июля 2010

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)
51 голосов
/ 21 июля 2010

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

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

27 голосов
/ 21 июля 2010

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

14 голосов
/ 25 мая 2017

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

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

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

12 голосов
/ 21 июня 2017

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

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

7 голосов
/ 03 ноября 2017

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

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

CPython dictobject.c

2 голосов
/ 31 декабря 2015

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...