Перебор элементов словаря(), значений(), ключей() в Python 3

Если я правильно понимаю, в Python 2 iter(d.keys()) было таким же, как d.iterkeys(). Но теперь d.keys() — это представление, которое находится между списком и итератором. В чем разница между представлением и итератором?

Другими словами, в Python 3, какая разница между

for k in d.keys()
    f(k)

и

for k in iter(d.keys())
    f(k)

Кроме того, как эти различия проявляются в простом цикле for (если вообще проявляются)?


person max    schedule 01.09.2010    source источник


Ответы (1)


Я не уверен, что это полноценный ответ на ваши вопросы, но, надеюсь, он немного объясняет разницу между Python 2 и 3 в этом отношении.

В Python 2 iter(d.keys()) и d.iterkeys() не совсем эквивалентны, хотя ведут себя одинаково. В первом случае keys() вернет копию списка ключей словаря, а iter затем вернет объект итератора по этому списку, а во втором случае копия полного списка ключей никогда не создается.

Объекты представления, возвращаемые d.keys() в Python 3, являются итерируемыми (т. е. из них можно сделать итератор), поэтому, когда вы говорите, for k in d.keys() Python создаст итератор для вас. Поэтому ваши два примера будут вести себя одинаково.

Значение изменения типа возвращаемого значения для keys() заключается в том, что объект представления Python 3 является динамическим. то есть, если мы скажем ks = d.keys(), а затем добавим к d, то ks отразит это. В Python 2 keys() возвращает список всех ключей, которые в данный момент находятся в словаре. Сравнивать:

Питон 3

>>> d = { "first" : 1, "second" : 2 }
>>> ks = d.keys()
>>> ks
dict_keys(['second', 'first'])
>>> d["third"] = 3
>>> ks
dict_keys(['second', 'third', 'first'])

Питон 2.x

>>> d = { "first" : 1, "second" : 2 }
>>> ks = d.keys()
>>> ks
['second', 'first']
>>> d["third"] = 3
>>> ks
['second', 'first']

Поскольку keys() в Python 3 возвращает динамический объект, в Python 3 нет (и в нем нет необходимости) отдельного метода iterkeys.

Дополнительные разъяснения

В Python 3 keys() возвращает объект dict_keys, но если мы используем его в контексте цикла for for k in d.keys(), то итератор создается неявно. Таким образом, разница между for k in d.keys() и for k in iter(d.keys()) заключается в неявном и явном создании итератора.

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

>>> ks = d.keys()
>>> 'first' in ks
True
>>> 'second' in ks
True
>>> i = iter(d.keys())
>>> 'first' in i
True
>>> 'second' in i
False             # because we've already reached the end of the iterator

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

>>> i2 = iter(d.keys())
>>> d['fourth'] = 4
>>> for k in i2: print(k)
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration

В Python 2, учитывая существующее поведение keys, требовался отдельный метод, чтобы обеспечить способ итерации без копирования списка ключей, сохраняя при этом обратную совместимость. Отсюда iterkeys()

person mikej    schedule 01.09.2010
comment
есть .viewkeys() в 2.7. который возвращает вид. docs.python.org/library/stdtypes.html#dict.viewkeys - person phadej; 01.09.2010
comment
Спасибо. Я понимаю, чем отличается d.keys() Python 2. Но я все еще не понимаю разницы между d.iterkeys() из Python 2, d.keys() из Python 3 и iter(d.keys()) из Python 3. Насколько я понимаю, все они динамические, и ни один из них не создает список заранее? - person max; 01.09.2010
comment
В цикле for нет разницы между iter(d.keys()) и d.keys(), так как python внутренне вызывает iter. Также нет разницы между python 2.x d.iterkeys() и py3k iter(d.keys()) : оба возвращают словарь-ключ-итератор. Так что все три практически одинаковы. - person phadej; 01.09.2010