Яка різниця між 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(). Він фактично створює повний об'єкт протоколу послідовності, який також відображає зміни в диктаті (і підтримується самим диктом, а не надмірним списком) - він підтримується на 2.7 як viewitems().
lvc

3
Я хотів би дізнатися про це детальніше, але мій google-fu не вдається. Чи міг би хтось вказати мені на документацію, статті чи джерела, які допоможуть мені краще зрозуміти це? @lvc?
Тушковане

10
@Sew зміна описана в 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.