Qual é a diferença entre dict.items () e dict.iteritems () no Python2?

705

Existem diferenças aplicáveis ​​entre dict.items()e dict.iteritems()?

Nos documentos do Python :

dict.items(): Retorna uma cópia da lista do dicionário de pares (chave, valor).

dict.iteritems(): Retorna um iterador sobre os pares do dicionário (chave, valor).

Se eu executar o código abaixo, cada um deles retornará uma referência ao mesmo objeto. Faltam algumas diferenças sutis?

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

Resultado:

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
o lobo
fonte
41
É basicamente uma diferença em como eles são computados. items()cria os itens de uma só vez e retorna uma lista. iteritems()retorna um gerador - um gerador é um objeto que "cria" um item de cada vez que next()é chamado a ele.
Joel Cornett
9
No seu caso particular, d[k] is vsempre retornaria True porque python mantém uma matriz de objetos inteiros para todos os números inteiros entre -5 e 256: docs.python.org/2/c-api/int.html Quando você cria um int nesse intervalo, na verdade, basta voltar uma referência ao objeto existente: >> a = 2; b = 2 >> a is b TrueMas,>> a = 1234567890; b = 1234567890 >> a is b False
t_tia 23/11
3
@ the_wolf Eu acho que seria melhor adicionar a versão python do documento que você está se referindo na pergunta.
Lorenzo Belli 12/01
2
Mudou iteritems()para iter()no Python 3? O link da documentação acima parece não corresponder a esta resposta.
Gabriel Staples
3
Não exatamente, @GabrielStaples. iteritems () é removido dos dicionários Python 3 e não tem substituição. No entanto, para o mesmo efeito, você usa iter (). por exemplo, iter (dict.items ()). Veja pep 469: python.org/dev/peps/pep-0469
Zim

Respostas:

863

Faz parte de uma evolução.

Originalmente, o Python items()construiu uma lista real de tuplas e a devolveu. Isso pode potencialmente levar muita memória extra.

Em seguida, os geradores foram introduzidos na linguagem em geral e esse método foi reimplementado como um método de gerador de iterador chamado iteritems(). O original permanece para compatibilidade com versões anteriores.

Uma das mudanças do Python 3 é que items()agora retornamos iteradores e uma lista nunca é totalmente criada. O iteritems()método também se foi, já que items()no Python 3 funciona como viewitems()no Python 2.7.

Keith
fonte
159
Observe que você perdeu um passo na evolução: o comportamento do Py3 não é o mesmo que iteritems(). Na verdade, ele cria um objeto de protocolo de sequência completo que também reflete as alterações no dict (e é suportado pelo próprio dict, em vez de uma lista redundante) - foi portado para 2.7 as viewitems().
lvc 5/05
3
Eu gostaria de aprender sobre isso com mais detalhes, mas meu google-fu está falhando comigo. Alguém poderia me indicar documentação, artigos ou fonte que me ajudassem a entender melhor isso? @lvc?
Guisado
10
@Stew a mudança é descrita no PEP 3106 e há um pouco mais no que há de novo em python 3.0
Tadhg McDonald-Jensen
1
Desculpe por elaborar essa pergunta antiga, mas entendo corretamente que iteritems()sempre é preferível aoitems() Python 2.x?
RubenGeert 11/1118
2
@RubenGeert Na maioria das vezes, isso não importa. Para ditados realmente grandes, pode ser preferível.
Keith
95

dict.items()retorna uma lista de 2-tuplas ( [(key, value), (key, value), ...]), enquanto que dict.iteritems()é um gerador que gera 2-tuplas. O primeiro ocupa mais espaço e tempo inicialmente, mas o acesso a cada elemento é rápido, enquanto o segundo ocupa menos espaço e tempo, mas um pouco mais na geração de cada elemento.

Ignacio Vazquez-Abrams
fonte
9
Por que você esperaria que eles fossem diferentes?
Ignacio Vazquez-Abrams
3
A "cópia" nos documentos não significa que os elementos são copiados (se você desejar, use copy.deepcopy). Isso significa que é uma cópia dos itens do dicionário: se você faz items = dct.items()e modifica dctadicionando / excluindo chaves ou dct[k] = other_v, itemspermanecerá o mesmo.
Dougal
4
Nada no Python é uma cópia profunda, a menos que seja explicitamente documentado como tal.
Karl Knechtel 5/05
1
@ IgnacioVazquez-Abrams - Quanto a "mais espaço e tempo": em que tamanho do dicionário eles começam a importar. Digamos que eu tenha um dicionário "grande" {1:'one', 2:'two', ... }sobre o qual desejo iterar em um servidor da web e renderizar os resultados. Em que escala devo começar a me preocupar em escolher o .items()vs .iteritems()para o Python 2.7?
User
1
@uffer: Não tenho certeza. Minha estimativa seria de 15 a 20 itens, mas ainda não testei.
Ignacio Vazquez-Abrams
64

No Py2.x

Os comandos dict.items(), dict.keys()e dict.values()retornar uma cópia do de dicionário lista de (k, v)pares, chaves e valores. Isso pode levar muita memória se a lista copiada for muito grande.

Os comandos dict.iteritems(), dict.iterkeys()e dict.itervalues()retornar um iterador sobre o dicionário (k, v)de pares, chaves e valores.

Os comandos dict.viewitems(), dict.viewkeys()e dict.viewvalues()devolver os objetos de exibição , que podem refletir as mudanças do dicionário. ( delOu seja, se você incluir um item ou adicionar um (k,v)par no dicionário, o objeto de visualização poderá ser alterado automaticamente ao mesmo tempo.)

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

Enquanto estiver no Py3.x

Em Py3.x, as coisas são mais limpo, uma vez que não são apenas dict.items(), dict.keys()e dict.values()disponível, que retornar a vista objetos , assim como dict.viewitems()em Py2.x fez.

Mas

Assim como o @lvc observou, o objeto view não é o mesmo que o iterador ; portanto, se você deseja retornar um iterador no Py3.x, pode usar 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'>
YaOzI
fonte
34

Você perguntou: 'Existem diferenças aplicáveis ​​entre dict.items () e dict.iteritems ()'

Isso pode ajudar (no Python 2.x):

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

Você pode ver que d.items()retorna uma lista de tuplas da chave, pares de valores e d.iteritems()retorna um dicionário-itemiterator.

Como uma lista, d.items () pode fatiar:

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

Mas não teria um __iter__método:

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

Como iterador, o d.iteritems () não pode ser dividido em fatias:

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

Mas tem __iter__:

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

Portanto, os itens são os mesmos - o contêiner que os entrega é diferente. Uma é uma lista e a outra um iterador (dependendo da versão do Python ...)

Portanto, as diferenças aplicáveis ​​entre dict.items () e dict.iteritems () são as mesmas que as diferenças aplicáveis ​​entre uma lista e um iterador.

dawg
fonte
15

dict.items()retornar lista de tuplas e dict.iteritems()retornar objeto iterador de tupla no dicionário como (key,value). As tuplas são as mesmas, mas o contêiner é diferente.

dict.items()basicamente copia todo o dicionário na lista. Tente usar o código a seguir para comparar os tempos de execução de dict.items()e dict.iteritems(). Você verá a diferença.

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

Saída na minha máquina:

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

Isso mostra claramente que dictionary.iteritems()é muito mais eficiente.

Prabhu
fonte
4

Se você tem

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

No Python 2 , dict.items()copia cada tupla e retorna a lista de tuplas no dicionário, ie [(key1,value1), (key2,value2), ...]. As implicações são de que todo o dicionário é copiado para uma nova lista contendo tuplas

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

dict.iteritems()retorna o iterador do item do dicionário. O valor do item retornado também é o mesmo (key1,value1), (key2,value2), ..., ou seja , mas isso não é uma lista. Este é apenas o objeto do iterador do item do dicionário. Isso significa menos uso de memória (50% menos).

  • Lista como instantâneos mutáveis: d.items() -> list(d.items())
  • Objetos Iteradores: d.iteritems() -> iter(d.items())

As tuplas são as mesmas. Você comparou as tuplas em cada uma delas para obter a mesma.

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

No Python 3 , dict.items()retorna o objeto iterador. dict.iteritems () é removido para que não haja mais problemas.

Hary Bakta
fonte
4

dict.iteritemsdesapareceu no Python3.x Portanto, use iter(dict.items())para obter a mesma alocação de saída e memória

Tessaracter
fonte
1

Se você quiser uma maneira de iterar os pares de itens de um dicionário que funcione com o Python 2 e 3, tente algo como isto:

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

Use-o assim:

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

dict.iteritems(): fornece um iterador. Você pode usar o iterador em outros padrões fora do loop.

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')
ethplumber
fonte
-5

dict.iteritems () no python 2 é equivalente a dict.items () no python 3.

user128364
fonte
2
Isto está incorreto. A diferença já foi explicada nas respostas anteriores.
vaultah