Jaka jest różnica między dict.items () i dict.iteritems () w Python2?


704

Czy są jakieś istotne różnice między dict.items()i dict.iteritems()?

Z dokumentacji Pythona :

dict.items(): Zwraca kopię listy słownika par (klucz, wartość).

dict.iteritems(): Zwraca iterator nad parami słownika (klucz, wartość).

Jeśli uruchomię poniższy kod, wydaje się, że każdy zwraca odwołanie do tego samego obiektu. Czy brakuje mi subtelnych różnic?

#!/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'   

Wynik:

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
Zasadniczo jest to różnica w sposobie ich obliczania. items()tworzy elementy jednocześnie i zwraca listę. iteritems()zwraca generator - generator to obiekt, który „tworzy” jeden element za każdym razem, gdy next()jest do niego wywoływany.
Joel Cornett

9
W twoim konkretnym przypadku d[k] is vzawsze zwraca True, ponieważ Python utrzymuje tablicę obiektów całkowitych dla wszystkich liczb całkowitych od -5 do 256: docs.python.org/2/c-api/int.html Kiedy tworzysz liczbę całkowitą w tym zakresie, po prostu odzyskam odniesienie do istniejącego obiektu: >> a = 2; b = 2 >> a is b TrueAle,>> a = 1234567890; b = 1234567890 >> a is b False
t_tia

3
@ wilk Myślę, że lepiej byłoby dodać dokumentację Pythona do dokumentu, którego dotyczy pytanie.
Lorenzo Belli

2
Czy iteritems()zmieniono na iter()w Python 3? Powyższy link do dokumentacji wydaje się nie pasować do tej odpowiedzi.
Gabriel Staples,

3
Niezupełnie @GabrielStaples. iteritems () jest usunięty ze słowników Python 3 i nie ma zamiany. Jednak dla tego samego efektu używasz iter (). np. iter (dict.items ()). Patrz pep 469: python.org/dev/peps/pep-0469
Zim

Odpowiedzi:


862

To część ewolucji.

Początkowo Python items()zbudował prawdziwą listę krotek i ją zwrócił. Może to potencjalnie zająć dużo dodatkowej pamięci.

Następnie generatory zostały wprowadzone do języka w ogóle, a metoda ta została ponownie zaimplementowana jako metoda iterator-generator o nazwie iteritems(). Oryginał pozostaje kompatybilny wstecz.

Jedną ze zmian w Pythonie 3 jest to, że items()teraz zwracają iteratory, a lista nigdy nie jest w pełni budowana. iteritems()Metoda jest również usunięte, ponieważ items()w Pythonie 3 działa podobnie jak viewitems()w Pythonie 2.7.


159
Zauważ, że przeoczyłeś krok w ewolucji: zachowanie Py3 nie jest takie samo jak iteritems(). W rzeczywistości tworzy obiekt z pełnym protokołem sekwencji, który również odzwierciedla zmiany w dyktcie (i jest wspierany przez sam dykt, a nie nadmiarową listę) - został przeniesiony do wersji 2.7 as viewitems().
lvc

3
Chciałbym dowiedzieć się o tym bardziej szczegółowo, ale moje google-fu mnie zawodzi. Czy ktoś mógłby skierować mnie do dokumentacji, artykułów lub źródła, które pomogłyby mi lepiej to zrozumieć? @lvc?
Gulasz

10
@ Odmiana zmiany została opisana w PEP 3106, a nowości w python 3.0
Tadhg McDonald-Jensen

1
Przepraszam za opracowanie tego starożytnego pytania, ale czy rozumiem poprawnie, że iteritems()zawsze jest ono lepsze niżitems() w Pythonie 2.x?
RubenGeert,

2
@RubenGeert Przez większość czasu nie ma to znaczenia. W przypadku naprawdę dużych nagrań może być lepiej.
Keith,

95

dict.items()zwraca listę 2-krotek ( [(key, value), (key, value), ...]), podczas gdy dict.iteritems()jest generatorem, który daje 2-krotki. Pierwszy z nich zajmuje początkowo więcej miejsca i czasu, ale dostęp do każdego elementu jest szybki, podczas gdy drugi zajmuje początkowo mniej miejsca i czasu, ale nieco więcej czasu na wygenerowanie każdego elementu.


9
Dlaczego miałbyś oczekiwać, że będą się różnić?
Ignacio Vazquez-Abrams

3
„Kopiuj” w dokumentach nie oznacza, że ​​elementy są kopiowane (jeśli chcesz, użyj copy.deepcopy). Oznacza to, że jest to kopia elementów słownika: jeśli to zrobisz, items = dct.items()a następnie zmodyfikujesz dct, dodając / usuwając klucze lub dct[k] = other_v, itemspozostanie bez zmian .
Dougal

4
Nic w Pythonie nigdy nie jest głęboką kopią, chyba że jest to wyraźnie udokumentowane.
Karl Knechtel

1
@ IgnacioVazquez-Abrams - Odnośnie „więcej miejsca i czasu”: przy jakim rozmiarze słownika zaczynają mieć znaczenie. Powiedzmy, że mam „duży” słownik, {1:'one', 2:'two', ... }nad którym chcę iterować na serwerze WWW i renderować wyniki. Na jakiej skali powinienem zacząć martwić się wyborem .items()vs .iteritems()dla Python 2.7?
użytkownik

1
@ bufer: Nie jestem do końca pewien. Szacuję, że będzie to 15-20 pozycji, ale tego nie testowałem.
Ignacio Vazquez-Abrams

64

W Py2.x

Komendy dict.items(), dict.keys()i dict.values()zwraca kopię słownika w liście od (k, v)pary, klucze i wartości. Może to zająć dużo pamięci, jeśli skopiowana lista jest bardzo duża.

Komendy dict.iteritems(), dict.iterkeys()i dict.itervalues()zwraca iterator nad słownika w (k, v)pary, klucze i wartości.

Komendy dict.viewitems(), dict.viewkeys()i dict.viewvalues()zwrotu przedmiotów zobacz , co może odzwierciedlać zmiany w słowniku. (Tj. Jeśli deldodasz element lub dodasz (k,v)parę do słownika, obiekt widoku może się automatycznie zmienić w tym samym czasie).

$ 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'>

Podczas gdy w Py3.x

W Py3.x rzeczy są bardziej czyste, ponieważ istnieje tylko dict.items(), dict.keys()i dict.values()są dostępne, które zwracają widok obiektów , tak jak dict.viewitems()w tak Py2.x.

Ale

Tak jak zauważył @lvc, obiekt widoku nie jest tym samym co iterator , więc jeśli chcesz zwrócić iterator w Py3.x, możesz użyć 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

Zapytałeś: „Czy są jakieś istotne różnice między dict.items () i dict.iteritems ()”

Może to pomóc (dla Python 2.x):

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

Możesz zobaczyć, że d.items()zwraca listę krotek klucza, par wartości i d.iteritems()zwraca słownik-itemiterator.

Jako listę, d.items () ma możliwość krojenia:

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

Ale nie miałby __iter__metody:

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

Jako iterator funkcja d.iteritems () nie obsługuje wycinania:

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

Ale ma __iter__:

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

Więc same przedmioty są takie same - pojemnik dostarczający przedmioty jest inny. Jedna to lista, druga iterator (w zależności od wersji Pythona ...)

Tak więc odpowiednie różnice między dict.items () i dict.iteritems () są takie same, jak obowiązujące różnice między listą a iteratorem.


15

dict.items()zwraca listę krotek i dict.iteritems()zwraca obiekt iteratora krotki w słowniku jako (key,value). Krotki są takie same, ale pojemnik jest inny.

dict.items()w zasadzie kopiuje cały słownik do listy. Spróbuj użyć następującego kodu, aby porównać czasy wykonania dict.items()i dict.iteritems(). Zobaczysz różnicę.

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

Dane wyjściowe w mojej maszynie:

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

To wyraźnie pokazuje, że dictionary.iteritems()jest znacznie bardziej wydajny.


4

Jeśli masz

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

W Pythonie 2 , dict.items()kopiuje każdy krotki i zwraca listę krotek w słowniku tj [(key1,value1), (key2,value2), ...]. Konsekwencją jest skopiowanie całego słownika na nową listę zawierającą krotki

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

dict.iteritems()zwraca iterator elementu słownika. Wartość zwracanego elementu jest również taka sama (key1,value1), (key2,value2), ..., ale nie jest to lista. Jest to tylko obiekt iteratora elementu słownika. Oznacza to mniejsze zużycie pamięci (50% mniej).

  • Wyświetla się jako zmienne migawki: d.items() -> list(d.items())
  • Obiekty iteratora: d.iteritems() -> iter(d.items())

Krotki są takie same. Porównywałeś krotki w każdym, więc otrzymujesz to samo.

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

W Pythonie 3 , dict.items()zwraca iterator obiektu. dict.iteritems () jest usunięty, więc nie ma już problemu.


4

dict.iteritemszniknął w Python3.x Więc użyj, iter(dict.items())aby uzyskać to samo wyjście i alokację pamięci


1

Jeśli chcesz znaleźć sposób na iterację par elementów słownika, który działa zarówno z Pythonem 2, jak i 3, spróbuj czegoś takiego:

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

Użyj tego w ten sposób:

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

0

dict.iteritems(): daje iterator. Możesz użyć iteratora w innych wzorach poza pętlą.

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 () w python 2 jest równoważne dict.items () w python 3.


2
To jest niepoprawne. Różnica została już wyjaśniona w poprzednich odpowiedziach.
vaultah
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.