Sự khác biệt giữa dict.items () và dict.iteritems () trong Python2 là gì?


705

Có sự khác biệt áp dụng giữa dict.items()dict.iteritems()?

Từ các tài liệu Python :

dict.items(): Trả về một bản sao của danh sách các cặp (khóa, giá trị) của từ điển.

dict.iteritems(): Trả về một trình vòng lặp qua các cặp (khóa, giá trị) của từ điển.

Nếu tôi chạy mã bên dưới, mỗi cái dường như trả về một tham chiếu đến cùng một đối tượng. Có sự khác biệt tinh tế mà tôi đang thiếu?

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

Đầu ra:

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
Về cơ bản, đó là một sự khác biệt trong cách chúng được tính toán. items()tạo tất cả các mục cùng một lúc và trả về một danh sách. iteritems()trả về một trình tạo - một trình tạo là một đối tượng "tạo ra" một mục tại một thời điểm mỗi lần next()được gọi trên nó.
Joel Cornett

9
Trong trường hợp cụ thể của bạn, d[k] is vsẽ luôn trả về True vì python giữ một mảng các đối tượng số nguyên cho tất cả các số nguyên trong khoảng từ -5 đến 256: docs.python.org/2/c-api/int.html Khi bạn tạo một int trong phạm vi đó thực sự chỉ cần lấy lại một tham chiếu đến đối tượng hiện có: >> a = 2; b = 2 >> a is b TrueNhưng,>> a = 1234567890; b = 1234567890 >> a is b False
t_tia

3
@the_wolf Tôi nghĩ sẽ tốt hơn nếu thêm phiên bản python của tài liệu mà bạn đang đề cập đến trong câu hỏi.
Lorenzo Belli

2
Đã iteritems()thay đổi iter()trong Python 3? Liên kết tài liệu ở trên dường như không khớp với câu trả lời này.
Gabriel Staples

3
Không chính xác, @GabrielStaples. iteritems () được xóa khỏi từ điển Python 3 và không có thay thế. Tuy nhiên, để có hiệu ứng tương tự, bạn sử dụng iter (). ví dụ: iter (dict.items ()). Xem pep 469: python.org/dev/peps/pep-0469
Zim

Câu trả lời:


863

Đó là một phần của sự tiến hóa.

Ban đầu, Python đã items()xây dựng một danh sách các bộ dữ liệu thực sự và trả lại nó. Điều đó có khả năng có thể mất rất nhiều bộ nhớ.

Sau đó, các trình tạo được đưa vào ngôn ngữ nói chung và phương thức đó được thực hiện lại như một phương thức trình tạo vòng lặp có tên iteritems(). Bản gốc vẫn còn tương thích ngược.

Một trong những thay đổi của Python 3 là items()bây giờ trả về các trình vòng lặp và một danh sách không bao giờ được xây dựng đầy đủ. Các iteritems()phương pháp cũng đã biến mất, kể từ items()bằng Python 3 công trình như viewitems()trong Python 2.7.


159
Lưu ý rằng bạn đã bỏ lỡ một bước trong quá trình tiến hóa: hành vi Py3 không giống như iteritems(). Nó thực sự tạo ra một đối tượng giao thức chuỗi đầy đủ cũng phản ánh các thay đổi đối với dict (và được hỗ trợ bởi chính dict, chứ không phải là một danh sách dự phòng) - nó đã được nhập vào 2.7 như viewitems().
lvc

3
Tôi muốn tìm hiểu về điều này chi tiết hơn, nhưng google-fu của tôi đang làm tôi thất vọng. Ai đó có thể chỉ cho tôi tài liệu, bài viết hoặc nguồn sẽ giúp tôi hiểu rõ hơn về điều này? @lvc?
Hầm

10
@Stew sự thay đổi được mô tả trong PEP 3106 và có thêm một chút về những gì mới trong python 3.0
Tadhg McDonald-Jensen

1
Xin lỗi vì đã xây dựng câu hỏi cổ xưa này nhưng tôi có hiểu chính xác iteritems()luôn luôn được ưu tiên hơnitems() trong Python 2.x không?
RubenGeert

2
@RubenGeert Hầu hết thời gian, nó không thành vấn đề. Đối với các dicts thực sự lớn nó có thể được ưa thích.
Keith

95

dict.items()trả về một danh sách 2-tuples ( [(key, value), (key, value), ...]), trong khi đó dict.iteritems()là một trình tạo mang lại 2-tuples. Cái trước mất nhiều không gian và thời gian ban đầu, nhưng việc truy cập từng phần tử thì nhanh, trong khi phần thứ hai mất ít không gian và thời gian ban đầu hơn, nhưng tốn thêm một chút thời gian để tạo từng phần tử.


9
Tại sao bạn mong đợi chúng khác nhau?
Ignacio Vazquez-Abrams

3
"Bản sao" trong tài liệu không có nghĩa là các phần tử được sao chép (nếu bạn muốn điều đó, hãy sử dụng copy.deepcopy). Điều đó có nghĩa là đó là bản sao của các mục từ điển: nếu bạn thực hiện items = dct.items()và sau đó sửa đổi dctbằng cách thêm / xóa các khóa hoặc dct[k] = other_v, itemssẽ giữ nguyên.
Dougal

4
Không có gì trong Python là bản sao sâu trừ khi được ghi lại rõ ràng như vậy.
Karl Knechtel

1
@ IgnacioVazquez-Abrams - Liên quan đến "nhiều không gian và thời gian hơn": Họ bắt đầu quan trọng ở mức độ nào của từ điển. Giả sử tôi có một từ điển "lớn" {1:'one', 2:'two', ... }mà tôi muốn lặp lại trên máy chủ web và hiển thị kết quả. Ở quy mô nào tôi nên bắt đầu lo lắng về việc chọn .items()vs .iteritems()Python 2.7?
người dùng

1
@buffer: Không chắc lắm. Ước tính của tôi sẽ là 15-20 mặt hàng, nhưng tôi chưa thử nghiệm điều đó.
Ignacio Vazquez-Abrams

64

Trong Py2.x

Các lệnh dict.items(), dict.keys()dict.values()trả về một bản sao của của từ điển danh sách của(k, v) cặp, khóa và giá trị. Điều này có thể mất rất nhiều bộ nhớ nếu danh sách sao chép là rất lớn.

Các lệnh dict.iteritems(), dict.iterkeys()dict.itervalues()trả về một iterator qua của từ điển (k, v)cặp, khóa và giá trị.

Các lệnh dict.viewitems(), dict.viewkeys()dict.viewvalues()trả lại đối tượng xem , có thể phản ánh những thay đổi của từ điển. (Tức là nếu bạn delmột mục hoặc thêm một (k,v)cặp trong từ điển, đối tượng xem có thể tự động thay đổi cùng một lúc.)

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

Trong khi ở Py3.x

Trong Py3.x, mọi thứ được sạch sẽ hơn, kể từ khi có chỉ là dict.items(), dict.keys()dict.values()có sẵn, mà trả lại xem đối tượng cũng giống nhưdict.viewitems() trong Py2.x đã làm.

Nhưng

Như @lvc đã lưu ý, đối tượng xem không giống như iterator , vì vậy nếu bạn muốn trả về một iterator trong Py3.x, bạn có thể sử dụng 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

Bạn đã hỏi: 'Có sự khác biệt nào có thể áp dụng giữa dict.items () và dict.iteritems ()'

Điều này có thể giúp (cho Python 2.x):

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

Bạn có thể thấy rằng d.items()trả về một danh sách các bộ khóa, cặp giá trị vàd.iteritems() trả về một trình phân loại từ điển.

Là một danh sách, d.items () là lát cắt có thể:

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

Nhưng sẽ không có một __iter__phương pháp:

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

Là một trình vòng lặp, d.iteritems () không thể cắt lát:

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

Nhưng có __iter__:

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

Vì vậy, các mặt hàng là như nhau - container cung cấp các mặt hàng là khác nhau. Một là danh sách, cái còn lại là một trình vòng lặp (tùy thuộc vào phiên bản Python ...)

Vì vậy, sự khác biệt có thể áp dụng giữa dict.items () và dict.iteritems () giống như sự khác biệt có thể áp dụng giữa danh sách và iterator.


15

dict.items()trả về danh sách các bộ dữ liệu và dict.iteritems()trả về đối tượng lặp của bộ dữ liệu trong từ điển dưới dạng (key,value). Các bộ dữ liệu là như nhau, nhưng container là khác nhau.

dict.items()về cơ bản sao chép tất cả từ điển vào danh sách. Hãy thử sử dụng mã sau đây để so sánh thời gian thực hiện của dict.items()dict.iteritems(). Bạn sẽ thấy sự khác biệt.

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

Đầu ra trong máy của tôi:

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

Điều này rõ ràng cho thấy rằng dictionary.iteritems()hiệu quả hơn nhiều.


4

Nếu bạn có

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

Trong Python 2 , dict.items()sao chép từng bộ dữ liệu và trả về danh sách các bộ dữ liệu trong từ điển tức là [(key1,value1), (key2,value2), ...]. Hàm ý là toàn bộ từ điển được sao chép vào danh sách mới chứa các bộ dữ liệu

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

dict.iteritems()trả về mục từ điển lặp. Giá trị của mục trả về cũng giống như vậy (key1,value1), (key2,value2), ..., nhưng đây không phải là danh sách. Đây chỉ là mục từ điển đối tượng lặp. Điều đó có nghĩa là sử dụng ít bộ nhớ hơn (ít hơn 50%).

  • Liệt kê dưới dạng ảnh chụp nhanh có thể thay đổi: d.items() -> list(d.items())
  • Các đối tượng lặp: d.iteritems() -> iter(d.items())

Các bộ dữ liệu là như nhau. Bạn so sánh các bộ dữ liệu trong mỗi bộ để bạn nhận được cùng.

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

Trong Python 3 , dict.items()trả về đối tượng iterator. dict.iteritems () đã bị xóa nên không còn vấn đề gì nữa.


4

dict.iteritemsđã biến mất trong Python3.x Vì vậy, hãy sử dụng iter(dict.items())để có cùng sự sắp xếp bộ nhớ và đầu ra


1

Nếu bạn muốn một cách lặp lại các cặp mục của một từ điển hoạt động với cả Python 2 và 3, hãy thử một cái gì đó như thế này:

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

Sử dụng nó như thế này:

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

0

dict.iteritems(): cung cấp cho bạn một trình vòng lặp. Bạn có thể sử dụng iterator trong các mẫu khác bên ngoài vòng lặp.

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 () trong python 2 tương đương với dict.items () trong python 3.


2
Điều này là không chính xác. Sự khác biệt đã được giải thích trong các câu trả lời trước.
vaultah
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.