ความแตกต่างระหว่าง dict.items () และ dict.iteritems () ใน Python2 คืออะไร?


705

มีความแตกต่างที่เกี่ยวข้องระหว่างdict.items()และdict.iteritems()?

จากPython docs :

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()มีการเรียกมัน
Joel Cornett

9
ในกรณีเฉพาะของคุณd[k] is vจะคืนค่าเป็น True เสมอเนื่องจากไพ ธ อนเก็บอาเรย์ของวัตถุจำนวนเต็มสำหรับจำนวนเต็มทั้งหมดระหว่าง -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 ฉันคิดว่าจะเป็นการดีกว่าถ้าคุณเพิ่มเอกสารหลามที่คุณอ้างถึงในคำถาม
Lorenzo Belli

2
ไม่iteritems()เปลี่ยนแปลงiter()ในหลาม 3 หรือไม่? ลิงค์เอกสารด้านบนดูเหมือนจะไม่ตรงกับคำตอบนี้
Gabriel Staples

3
ไม่ตรง @GabrielStaples iteritems () ถูกลบออกจากพจนานุกรม Python 3 และไม่มีการแทนที่ อย่างไรก็ตามสำหรับเอฟเฟกต์เดียวกันคุณใช้ iter () เช่น iter (dict.items ()) ดู pep 469: python.org/dev/peps/pep-0469
Zim

คำตอบ:


864

มันเป็นส่วนหนึ่งของวิวัฒนาการ

เดิมที Python items()สร้างรายการ tuples จริงและส่งคืนนั้น ซึ่งอาจใช้หน่วยความจำเพิ่มเติมเป็นจำนวนมาก

จากนั้นเครื่องกำเนิดไฟฟ้าถูกนำไปใช้ภาษาในทั่วไปและวิธีการที่ถูก reimplemented เป็นวิธี iterator iteritems()กำเนิดชื่อ ต้นฉบับยังคงอยู่สำหรับการเข้ากันได้ย้อนหลัง

หนึ่งในการเปลี่ยนแปลงของ Python 3 คือ items()ตอนนี้ส่งคืนตัววนซ้ำและรายการจะไม่ถูกสร้างขึ้นอย่างสมบูรณ์ iteritems()วิธีจะหายไปนอกจากนี้ตั้งแต่items()ในหลาม 3 งานเหมือนviewitems()ในหลาม 2.7


159
หมายเหตุที่คุณจะพลาดขั้นตอนในการวิวัฒนาการไปนี้: พฤติกรรม Py3 iteritems()ไม่ได้เช่นเดียวกับ มันจริงทำให้วัตถุลำดับโปรโตคอลเต็มรูปแบบที่ยังสะท้อนให้เห็นถึงการเปลี่ยนแปลง Dict (และมีการสนับสนุนจากกิงดิคของตัวเองมากกว่าที่จะเป็นรายการซ้ำซ้อน) - มันถูก backported 2.7 viewitems()เป็น
lvc

3
ฉันต้องการที่จะเรียนรู้เกี่ยวกับเรื่องนี้ในรายละเอียดมากขึ้น แต่ google-fu ของฉันล้มเหลวฉัน ใครช่วยชี้แนะฉันไปที่เอกสารบทความหรือแหล่งที่จะช่วยให้ฉันเข้าใจสิ่งนี้ดีขึ้น? @lvc?
Stew

10
@Stew การเปลี่ยนแปลงอธิบายไว้ในPEP 3106และมีอะไรใหม่ใน python 3.0
Tadhg McDonald-Jensen

1
ขออภัยที่อธิบายอย่างละเอียดเกี่ยวกับคำถามโบราณนี้ แต่ฉันเข้าใจถูกต้องหรือไม่ว่าiteritems()จะเป็นitems() Python 2.x?
RubenGeert

2
@RubenGeert ส่วนใหญ่เวลามันไม่สำคัญ สำหรับ dicts ขนาดใหญ่จริง ๆ มันอาจจะดีกว่า
Keith

95

dict.items()ส่งคืนรายการของ 2-tuples ( [(key, value), (key, value), ...]) ในขณะที่dict.iteritems()เป็นตัวกำเนิดที่ให้ผลลัพธ์ 2-tuples อดีตใช้พื้นที่และเวลามากขึ้นในขั้นต้น แต่การเข้าถึงแต่ละองค์ประกอบนั้นเร็วในขณะที่อันดับที่สองใช้พื้นที่และเวลาน้อยลงในขั้นต้น แต่ใช้เวลาเพิ่มขึ้นเล็กน้อยในการสร้างแต่ละองค์ประกอบ


9
ทำไมคุณคาดหวังให้พวกเขาแตกต่างกัน
Ignacio Vazquez-Abrams

3
"คัดลอก" ในเอกสารไม่ได้หมายความว่าองค์ประกอบจะถูกคัดลอก (ถ้าคุณต้องการใช้copy.deepcopy) มันหมายความว่ามันเป็นสำเนาของรายการที่พจนานุกรม: ถ้าคุณทำitems = dct.items()แล้วปรับเปลี่ยนdctโดยการเพิ่ม / ลบคีย์หรือdct[k] = other_v, itemsจะยังเหมือนเดิม
Dougal

4
ไม่มีสิ่งใดใน Python ที่จะคัดลอกแบบลึกยกเว้นว่ามีการบันทึกไว้อย่างชัดเจน
Karl Knechtel

1
@ IgnacioVazquez-Abrams - เกี่ยวกับ "พื้นที่และเวลามากขึ้น": ขนาดของพจนานุกรมที่พวกเขาเริ่มมีความสำคัญ สมมติว่าฉันเป็นพจนานุกรม "ใหญ่" {1:'one', 2:'two', ... }ที่ฉันต้องการทำซ้ำในเว็บเซิร์ฟเวอร์และแสดงผลลัพธ์ ฉันควรเริ่มกังวลกับการเลือก.items()vs .iteritems()สำหรับ Python 2.7 ในระดับใด
ผู้ใช้

1
@buffer: ไม่แน่ใจจริงๆ ค่าประมาณของฉันจะเป็น 15-20 รายการ แต่ฉันยังไม่ได้ทดสอบ
Ignacio Vazquez-Abrams

64

ใน Py2.x

คำสั่งdict.items(), dict.keys()และdict.values()ส่งคืนสำเนาของพจนานุกรมของรายการของ(k, v)คู่คีย์และค่า การดำเนินการนี้อาจใช้หน่วยความจำมากถ้ารายการที่คัดลอกมีขนาดใหญ่มาก

คำสั่งdict.iteritems(), dict.iterkeys()และdict.itervalues()กลับiteratorกว่าพจนานุกรมของ(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 ที่บันทึกไว้มุมมองวัตถุไม่เหมือนกับiteratorดังนั้นหากคุณต้องการส่งคืน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()ส่งคืนรายการของ tuples ของคีย์คู่ค่าและd.iteritems()ส่งคืน dictionary-itemiterator

ในฐานะรายการ 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

ในฐานะ 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()รายการ tuples กลับมาและdict.iteritems()กลับวัตถุ iterator ของ tuple (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,...}

ในหลาม 2 , dict.items()สำเนา tuples แต่ละคนและผลตอบแทนที่รายการ tuples [(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())
  • วัตถุ Iterator: 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)

ในหลาม 3 , dict.items()ผลตอบแทนวัตถุ iterator 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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.