Python2中的dict.items()和dict.iteritems()有什么区别?


704

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版本。
Lorenzo Belli

2
有没有iteritems()改变iter()在Python 3?上面的文档链接似乎与此答案不符。
加布里埃尔·斯台普斯

3
不完全是@GabrielStaples。iteritems()已从字典Python 3中删除,并且不能替代。但是,为了达到相同的效果,请使用iter()。例如iter(dict.items())。见pep 469:python.org/dev/peps/pep-0469
Zim

Answers:


862

这是演变的一部分。

最初,Python items()构建了一个真正的元组列表,并将其返回。这可能会占用大量额外的内存。

然后,一般将生成器引入该语言,然后将该方法重新实现为名为的迭代器-生成器方法iteritems()。保留原始版本是为了向后兼容。

Python 3的更改之一是 items()现在返回迭代器,并且列表从未完全构建。该iteritems()方法也消失了,因为items()在Python 3中的工作方式与viewitems()在Python 2.7中一样。


159
请注意,您错过了进化的一步:Py3的行为与相同iteritems()。实际上,它制作了一个完整的序列协议对象,该对象也反映了dict的更改(并由dict本身支持,而不是冗余列表)-它已反向移植为2.7 viewitems()
lvc 2012年

3
我想更详细地了解这一点,但是我的google-fu让我失望了。有人可以指出我的文档,文章或资源来帮助我更好地理解这一点吗?@lvc?


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_vitems则将保持不变。
2012年

4
除非明确记录,否则Python中的任何内容都不是深度复制。
Karl Knechtel

1
@ IgnacioVazquez-Abrams-关于“更多的空间和时间”:它们以什么大小的字典开始起作用。假设我有一本“大”字典{1:'one', 2:'two', ... },我想在该字典上在Web服务器上进行迭代并呈现结果。我应该开始担心在多大程度上选择.items()vs .iteritems()for 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指出的那样,view对象iterator并不相同,因此,如果要在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()已删除,因此不再有问题。


3

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

python 2中的dict.iteritems()与python 3中的dict.items()等效。


2
这是不正确的。先前的答案已经说明了差异。
vaultah '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.