В чем разница между dict.items () и dict.iteritems () в Python2?


705

Есть ли применимые различия между dict.items()и dict.iteritems()?

Из документов Python :

dict.items()Возвращает копию списка словаря пар (ключ, значение).

dict.iteritems()Возвращает итератор для пар слов (ключ, значение).

Если я запускаю приведенный ниже код, кажется, что каждый возвращает ссылку на один и тот же объект. Есть ли тонкие различия, которые я пропускаю?

#!/usr/bin/python

d={1:'one',2:'two',3:'three'}
print 'd.items():'
for k,v in d.items():
   if d[k] is v: print '\tthey are the same object' 
   else: print '\tthey are different'

print 'd.iteritems():'   
for k,v in d.iteritems():
   if d[k] is v: print '\tthey are the same object' 
   else: print '\tthey are different'   

Вывод:

d.items():
    they are the same object
    they are the same object
    they are the same object
d.iteritems():
    they are the same object
    they are the same object
    they are the same object

41
Это в основном разница в том, как они вычисляются. items()создает элементы сразу и возвращает список. iteritems()возвращает генератор - генератор - это объект, который «создает» один элемент за раз каждый раз, когда next()к нему обращаются.
Джоэл Корнетт

9
В вашем конкретном случае d[k] is vвсегда будет возвращать True, потому что python хранит массив целочисленных объектов для всех целых чисел от -5 до 256: docs.python.org/2/c-api/int.html Когда вы создаете int в этом диапазоне, вы на самом деле просто вернуть ссылку на существующий объект: >> a = 2; b = 2 >> a is b TrueНо,>> a = 1234567890; b = 1234567890 >> a is b False
t_tia

3
@the_wolf Я думаю, что было бы лучше добавить версию документа на Python, на которую вы ссылаетесь в вопросе.
Лоренцо Белли

2
Ли iteritems()изменения iter()в Python 3? Ссылка на документацию выше не соответствует этому ответу.
Габриэль Стейплс

3
Не совсем, @GabrielStaples. iteritems () удален из словарей Python 3 и не имеет замены. Однако для того же эффекта вы используете iter (). например, iter (dict.items ()). Смотрите pep 469: python.org/dev/peps/pep-0469
Zim

Ответы:


864

Это часть эволюции.

Первоначально Python items()создал реальный список кортежей и вернул его. Это может занять много дополнительной памяти.

Затем генераторы были введены в язык в целом, и этот метод был переопределен как метод итератор-генератор с именем iteritems(). Оригинал остается для обратной совместимости.

Одно из изменений Python 3 состоит в том, что items()теперь возвращаются итераторы, а список никогда не создается полностью. iteritems()Метод также нет, так как items()в Python 3 работает как viewitems()в Python 2.7.


159
Обратите внимание, что вы пропустили шаг в эволюции: поведение Py3 не совпадает с iteritems(). Фактически он создает полный объект протокола последовательности, который также отражает изменения в dict (и поддерживается самим dict, а не избыточным списком) - он был перенесен в 2.7 as viewitems().
lvc

3
Я хотел бы узнать об этом более подробно, но мой гугл-фу меня подводит. Может ли кто-нибудь указать мне на документацию, статьи или источник, который поможет мне лучше понять это? @lvc?
рагу

10
@ Остановимся на изменениях, описанных в PEP 3106, и есть еще кое-что в том, что нового в Python 3.0
Tadhg McDonald-Jensen,

1
Извините за разработку этого древнего вопроса, но правильно ли я понимаю, что iteritems()всегда предпочтительнее, чемitems() в Python 2.x?
RubenGeert

2
@RubenGeert В большинстве случаев это не имеет значения. Для действительно больших диктов это может быть предпочтительнее.
Кит

95

dict.items()возвращает список 2-кортежей ( [(key, value), (key, value), ...]), тогда dict.iteritems()как это генератор, который выдает 2-кортежа. Первый занимает больше места и времени на начальном этапе, но доступ к каждому элементу происходит быстро, тогда как второй занимает меньше места и времени на начальном этапе, но немного больше времени при создании каждого элемента.


9
Почему вы ожидаете, что они будут другими?
Игнасио Васкес-Абрамс

3
«Копировать» в документах не означает, что элементы копируются (если хотите, используйте copy.deepcopy). Это означает, что это копия элементов словаря: если вы сделаете, items = dct.items()а затем измените dct, добавив / удалив ключи или dct[k] = other_v, itemsостанетесь прежними.
Дугал

4
Ничто в Python не является глубокой копией, если не указано иное.
Карл Кнехтель

1
@ IgnacioVazquez-Abrams - Что касается «большего пространства и времени»: при каком размере словаря они начинают иметь значение. Скажем, у меня есть «большой» словарь, {1:'one', 2:'two', ... }по которому я хочу перебрать веб-сервер и отобразить результаты. В каком масштабе я должен начать беспокоиться о выборе .items()vs .iteritems()для Python 2.7?
пользователь

1
@buffer: Не совсем уверен. Моя оценка будет 15-20 пунктов, но я не проверял это.
Игнасио Васкес-Абрамс

64

В Py2.x

Команды dict.items(), dict.keys()и dict.values()возвращает копию из словаря список из (k, v)пары, ключей и значений. Это может занять много памяти, если скопированный список очень большой.

Команды dict.iteritems(), dict.iterkeys()и dict.itervalues()возвращает итератор над Словаре в (k, v)пару, ключей и значений.

Команды dict.viewitems(), dict.viewkeys()и dict.viewvalues()возвращают вид объекты , которые могут отражать изменения в словаре. (То есть, если вы delдобавляете элемент или добавляете (k,v)пару в словарь, вид объекта может автоматически изменяться одновременно.)

$ python2.7

>>> d = {'one':1, 'two':2}
>>> type(d.items())
<type 'list'>
>>> type(d.keys())
<type 'list'>
>>> 
>>> 
>>> type(d.iteritems())
<type 'dictionary-itemiterator'>
>>> type(d.iterkeys())
<type 'dictionary-keyiterator'>
>>> 
>>> 
>>> type(d.viewitems())
<type 'dict_items'>
>>> type(d.viewkeys())
<type 'dict_keys'>

Пока в Py3.x

В Py3.x, все более чистые, так как есть только dict.items(), dict.keys()и dict.values()доступны, которые возвращают вид объекты так же , как dict.viewitems()в сделал Py2.x.

Но

Как заметил @lvc, объект представления не совпадает с итератором , поэтому, если вы хотите вернуть итератор в Py3.x, вы можете использовать iter(dictview):

$ python3.3

>>> d = {'one':'1', 'two':'2'}
>>> type(d.items())
<class 'dict_items'>
>>>
>>> type(d.keys())
<class 'dict_keys'>
>>>
>>>
>>> ii = iter(d.items())
>>> type(ii)
<class 'dict_itemiterator'>
>>>
>>> ik = iter(d.keys())
>>> type(ik)
<class 'dict_keyiterator'>

34

Вы спросили: «Существуют ли какие-либо применимые различия между dict.items () и dict.iteritems ()»

Это может помочь (для Python 2.x):

>>> d={1:'one',2:'two',3:'three'}
>>> type(d.items())
<type 'list'>
>>> type(d.iteritems())
<type 'dictionary-itemiterator'>

Вы можете видеть, что d.items()возвращает список кортежей ключа, пары значений и d.iteritems()возвращает словарь-элементитератор.

Как список, d.items () может работать с фрагментами:

>>> l1=d.items()[0]
>>> l1
(1, 'one')   # an unordered value!

Но не было бы __iter__метода:

>>> next(d.items())
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: list object is not an iterator

Как итератор, d.iteritems () не может работать с секциями :

>>> i1=d.iteritems()[0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'dictionary-itemiterator' object is not subscriptable

Но имеет __iter__:

>>> next(d.iteritems())
(1, 'one')               # an unordered value!

Таким образом, сами предметы одинаковы - контейнер для доставки предметов различен. Один - список, другой - итератор (в зависимости от версии Python ...)

Таким образом, применимые различия между dict.items () и dict.iteritems () такие же, как применимые различия между списком и итератором.


15

dict.items()вернуть список кортежей и dict.iteritems()вернуть объект итератора кортежа в словарь как (key,value). Кортежи одинаковые, но контейнер другой.

dict.items()в основном копирует весь словарь в список. Попробуйте использовать следующий код, чтобы сравнить время выполнения dict.items()и dict.iteritems(). Вы увидите разницу.

import timeit

d = {i:i*2 for i in xrange(10000000)}  
start = timeit.default_timer() #more memory intensive
for key,value in d.items():
    tmp = key + value #do something like print
t1 = timeit.default_timer() - start

start = timeit.default_timer()
for key,value in d.iteritems(): #less memory intensive
    tmp = key + value
t2 = timeit.default_timer() - start

Выход в моей машине:

Time with d.items(): 9.04773592949
Time with d.iteritems(): 2.17707300186

Это ясно показывает, что dictionary.iteritems()это гораздо эффективнее.


4

Если у тебя есть

dict = {key1:value1, key2:value2, key3:value3,...}

В Python 2 , dict.items()копирует каждый кортежи и возвращает список кортежей в словаре т.е. [(key1,value1), (key2,value2), ...]. Это означает, что весь словарь копируется в новый список, содержащий кортежи

dict = {i: i * 2 for i in xrange(10000000)}  
# Slow and memory hungry.
for key, value in dict.items():
    print(key,":",value)

dict.iteritems()возвращает итератор элемента словаря Значение возвращаемого элемента также то же самое, т. (key1,value1), (key2,value2), ...Е. Это не список. Это всего лишь объект итератора элемента словаря. Это означает меньшее использование памяти (на 50% меньше).

  • Списки как изменяемые снимки: d.items() -> list(d.items())
  • Объекты итератора: d.iteritems() -> iter(d.items())

Кортежи одинаковы. Вы сравнили кортежи в каждом, так что вы получите то же самое.

dict = {i: i * 2 for i in xrange(10000000)}  
# More memory efficient.
for key, value in dict.iteritems():
    print(key,":",value)

В Python 3 , dict.items()возвращает итератор объекта. dict.iteritems () удален, поэтому больше нет проблем.


4

dict.iteritemsотсутствует в Python3.x Так что используйте, iter(dict.items())чтобы получить тот же вывод и распределение памяти


1

Если вам нужен способ итерации пар элементов словаря, который работает с Python 2 и 3, попробуйте что-то вроде этого:

DICT_ITER_ITEMS = (lambda d: d.iteritems()) if hasattr(dict, 'iteritems') else (lambda d: iter(d.items()))

Используйте это так:

for key, value in DICT_ITER_ITEMS(myDict):
    # Do something with 'key' and/or 'value'.

0

dict.iteritems(): дает вам итератор. Вы можете использовать итератор в других шаблонах вне цикла.

student = {"name": "Daniel", "student_id": 2222}

for key,value in student.items():
    print(key,value)

('student_id', 2222)
('name', 'Daniel')

for key,value in student.iteritems():
    print(key,value)

('student_id', 2222)
('name', 'Daniel')

studentIterator = student.iteritems()

print(studentIterator.next())
('student_id', 2222)

print(studentIterator.next())
('name', 'Daniel')

-5

dict.iteritems () в python 2 эквивалентен dict.items () в python 3.


2
Это неверно Разница уже была объяснена в предыдущих ответах.
vaultah
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.