Lặp lại từ điển bằng cách sử dụng các vòng lặp 'cho'


3138

Tôi hơi bối rối bởi đoạn mã sau:

d = {'x': 1, 'y': 2, 'z': 3} 
for key in d:
    print key, 'corresponds to', d[key]

Những gì tôi không hiểu là keyphần. Làm thế nào để Python nhận ra rằng nó chỉ cần đọc khóa từ từ điển? Là keymột từ đặc biệt trong Python? Hay nó chỉ đơn giản là một biến số?


3
Trước khi bạn đăng câu trả lời mới, hãy xem xét đã có hơn 10 câu trả lời cho câu hỏi này. Xin vui lòng, đảm bảo rằng câu trả lời của bạn đóng góp thông tin không nằm trong số các câu trả lời hiện có.
janniks

Câu trả lời:


5393

key chỉ là một tên biến.

for key in d:

sẽ chỉ đơn giản lặp lại các khóa trong từ điển, thay vì các khóa và giá trị. Để lặp qua cả khóa và giá trị, bạn có thể sử dụng như sau:

Đối với Python 3.x:

for key, value in d.items():

Đối với Python 2.x:

for key, value in d.iteritems():

Để tự kiểm tra, thay đổi từ keythành poop.

Trong Python 3.x, iteritems()đã được thay thế bằng cách đơn giản items(), nó trả về một khung nhìn giống như được thiết lập được hỗ trợ bởi dict, thích iteritems()nhưng thậm chí còn tốt hơn. Điều này cũng có sẵn trong 2.7 như viewitems().

Thao tác items()sẽ hoạt động cho cả 2 và 3, nhưng trong 2, nó sẽ trả về một danh sách các (key, value)cặp từ điển , điều này sẽ không phản ánh các thay đổi đối với chính tả xảy ra sau items()cuộc gọi. Nếu bạn muốn hành vi 2.x trong 3.x, bạn có thể gọi list(d.items()).


158
Thêm một lý do bị bỏ qua để không truy cập giá trị như thế này: d [key] bên trong vòng lặp for khiến khóa được băm lại (để lấy giá trị). Khi từ điển lớn, hàm băm bổ sung này sẽ thêm vào tổng thời gian. Điều này được thảo luận trong buổi nói chuyện công nghệ của Raymond Hettinger youtube.com/watch?v=anrOzOapJ2E
quiet_penguin

27
Có thể có ý nghĩa để đề cập rằng các mục sẽ được lặp đi lặp lại theo thứ tự không thể đoán trước và sortedcần thiết để ổn định nó.
yugr

5
@HarisankarKrishnaSwamy thay thế là gì?
JoeyC

3
@yugr Tại sao bạn nói vậy? Các tài liệu nói Keys and values are iterated over in insertion order. [ docs.python.org/3/l Library / Mạnh
Geza Turi

4
@yugr Từ Python 3.7, từ điển được sắp xếp theo thứ tự và đây là một tính năng ngôn ngữ. Xem stackoverflow.com/a/39980744/9428564
Aimery

433

Đó không phải là khóa đó là một từ đặc biệt, nhưng từ điển đó thực hiện giao thức lặp. Bạn có thể làm điều này trong lớp của bạn, ví dụ: xem câu hỏi này để biết cách xây dựng các trình vòng lặp lớp.

Trong trường hợp từ điển, nó được thực hiện ở cấp độ C. Các chi tiết có sẵn trong PEP 234 . Cụ thể, phần có tiêu đề "Từ điển lặp":

  • Từ điển thực hiện một khe tp_iter trả về một trình vòng lặp hiệu quả lặp lại các khóa của từ điển. [...] Điều này có nghĩa là chúng ta có thể viết

    for k in dict: ...

    tương đương với, nhưng nhanh hơn nhiều

    for k in dict.keys(): ...

    miễn là hạn chế sửa đổi từ điển (theo vòng lặp hoặc bởi luồng khác) không bị vi phạm.

  • Thêm phương thức vào từ điển trả về các loại trình lặp khác nhau một cách rõ ràng:

    for key in dict.iterkeys(): ...
    
    for value in dict.itervalues(): ...
    
    for key, value in dict.iteritems(): ...

    Điều này có nghĩa for x in dictlà tốc ký cho for x in dict.iterkeys().

Trong Python 3, dict.iterkeys(), dict.itervalues()dict.iteritems()không còn được hỗ trợ. Sử dụng dict.keys(), dict.values()dict.items()thay vào đó.


207

Lặp lại qua một lần dictlặp thông qua các khóa của nó không theo thứ tự cụ thể, như bạn có thể thấy ở đây:

Chỉnh sửa: (Đây không còn là trường hợp trong Python3.6 , nhưng lưu ý rằng đó chưa phải là hành vi được đảm bảo )

>>> d = {'x': 1, 'y': 2, 'z': 3} 
>>> list(d)
['y', 'x', 'z']
>>> d.keys()
['y', 'x', 'z']

Ví dụ của bạn, đó là một ý tưởng tốt hơn để sử dụng dict.items():

>>> d.items()
[('y', 2), ('x', 1), ('z', 3)]

Điều này cung cấp cho bạn một danh sách các bộ dữ liệu. Khi bạn lặp lại chúng như thế này, mỗi bộ dữ liệu sẽ được giải nén kvtự động:

for k,v in d.items():
    print(k, 'corresponds to', v)

Sử dụng kvlàm tên biến khi lặp qua a dictlà khá phổ biến nếu phần thân của vòng lặp chỉ có một vài dòng. Đối với các vòng lặp phức tạp hơn, có thể nên sử dụng các tên mô tả nhiều hơn:

for letter, number in d.items():
    print(letter, 'corresponds to', number)

Đó là một ý tưởng tốt để tập thói quen sử dụng các chuỗi định dạng:

for letter, number in d.items():
    print('{0} corresponds to {1}'.format(letter, number))

11
Từ ghi chú phát hành Python 3.7: "Bản chất bảo quản thứ tự chèn của các đối tượng dict hiện là một phần chính thức của đặc tả ngôn ngữ Python."
Gregory Arenius

86

key chỉ đơn giản là một biến.

Đối với Python2.X :

d = {'x': 1, 'y': 2, 'z': 3} 
for my_var in d:
    print my_var, 'corresponds to', d[my_var]

... hoặc tốt hơn,

d = {'x': 1, 'y': 2, 'z': 3} 
for the_key, the_value in d.iteritems():
    print the_key, 'corresponds to', the_value

Đối với Python3.X :

d = {'x': 1, 'y': 2, 'z': 3} 
for the_key, the_value in d.items():
    print(the_key, 'corresponds to', the_value)

63

Khi bạn lặp qua các từ điển bằng cách sử dụng for .. in ..-syntax, nó luôn lặp lại trên các khóa (các giá trị có thể truy cập bằng cách sử dụng dictionary[key]).

Để lặp lại các cặp khóa-giá trị, trong Python 2 sử dụng for k,v in s.iteritems()và trong Python 3 for k,v in s.items().


38
Lưu ý rằng đối với Python 3, nó items()thay vìiteritems()
Andreas Fester


19

Lặp lại từ điển bằng cách sử dụng các vòng lặp 'cho'

d = {'x': 1, 'y': 2, 'z': 3} 
for key in d:
    ...

Làm thế nào để Python nhận ra rằng nó chỉ cần đọc khóa từ từ điển? Khóa có phải là một từ đặc biệt trong Python không? Hay nó chỉ đơn giản là một biến số?

Đó không chỉ là forcác vòng lặp. Từ quan trọng ở đây là "lặp đi lặp lại".

Từ điển là ánh xạ các khóa tới các giá trị:

d = {'x': 1, 'y': 2, 'z': 3} 

Bất cứ khi nào chúng tôi lặp lại nó, chúng tôi lặp lại các phím. Tên biến keychỉ nhằm mục đích mô tả - và nó khá thích hợp cho mục đích này.

Điều này xảy ra trong một sự hiểu biết danh sách:

>>> [k for k in d]
['x', 'y', 'z']

Nó xảy ra khi chúng ta chuyển từ điển vào danh sách (hoặc bất kỳ đối tượng loại bộ sưu tập nào khác):

>>> list(d)
['x', 'y', 'z']

Cách Python lặp đi lặp lại, trong ngữ cảnh mà nó cần, nó gọi __iter__phương thức của đối tượng (trong trường hợp này là từ điển) trả về một iterator (trong trường hợp này là đối tượng keyiterator):

>>> d.__iter__()
<dict_keyiterator object at 0x7fb1747bee08>

Thay vào đó, chúng ta không nên sử dụng các phương thức đặc biệt này, sử dụng hàm dựng sẵn tương ứng để gọi nó , iter:

>>> key_iterator = iter(d)
>>> key_iterator
<dict_keyiterator object at 0x7fb172fa9188>

Các trình vòng lặp có một __next__phương thức - nhưng chúng ta gọi nó với hàm dựng sẵn , next:

>>> next(key_iterator)
'x'
>>> next(key_iterator)
'y'
>>> next(key_iterator)
'z'
>>> next(key_iterator)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

Khi một vòng lặp bị cạn kiệt, nó sẽ tăng lên StopIteration. Đây là cách Python biết để thoát khỏi một forvòng lặp, hoặc hiểu danh sách hoặc biểu thức trình tạo hoặc bất kỳ bối cảnh lặp nào khác. Khi một trình vòng lặp tăng lên, StopIterationnó sẽ luôn nâng nó lên - nếu bạn muốn lặp lại lần nữa, bạn cần một cái mới.

>>> list(key_iterator)
[]
>>> new_key_iterator = iter(d)
>>> list(new_key_iterator)
['x', 'y', 'z']

Quay trở lại

Chúng tôi đã nhìn thấy các dicts lặp đi lặp lại trong nhiều bối cảnh. Những gì chúng ta đã thấy là bất cứ khi nào chúng ta lặp đi lặp lại một lệnh, chúng ta sẽ nhận được các phím. Quay lại ví dụ ban đầu:

d = {'x': 1, 'y': 2, 'z': 3} 
for key in d:

Nếu chúng ta thay đổi tên biến, chúng ta vẫn nhận được các khóa. Hãy thử nó:

>>> for each_key in d:
...     print(each_key, '=>', d[each_key])
... 
x => 1
y => 2
z => 3

Nếu chúng ta muốn lặp lại các giá trị, chúng ta cần sử dụng .valuesphương thức dicts hoặc cho cả hai cùng nhau .items:

>>> list(d.values())
[1, 2, 3]
>>> list(d.items())
[('x', 1), ('y', 2), ('z', 3)]

Trong ví dụ đã cho, việc lặp lại các mục như thế này sẽ hiệu quả hơn:

for a_key, corresponding_value in d.items():
    print(a_key, corresponding_value)

Nhưng đối với mục đích học tập, ví dụ của câu hỏi là tốt.


17

Tôi có một trường hợp sử dụng trong đó tôi phải lặp qua dict để lấy khóa, cặp giá trị, cũng là chỉ số cho biết tôi đang ở đâu. Đây là cách tôi làm điều đó:

d = {'x': 1, 'y': 2, 'z': 3} 
for i, (key, value) in enumerate(d.items()):
   print(i, key, value)

Lưu ý rằng các dấu ngoặc đơn xung quanh khóa, giá trị là quan trọng, không có dấu ngoặc đơn, bạn nhận được ValueError "không đủ giá trị để giải nén".


1
Làm thế nào điều này có liên quan đến câu hỏi?
jorijnsmit

8

Bạn có thể kiểm tra việc triển khai CPython's dicttypetrên GitHub. Đây là chữ ký của phương thức thực hiện trình lặp dict:

_PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey,
             PyObject **pvalue, Py_hash_t *phash)

CPython dictobject.c


4

Để lặp lại các phím, nó chậm hơn nhưng tốt hơn để sử dụng my_dict.keys(). Nếu bạn đã cố gắng làm một cái gì đó như thế này:

for key in my_dict:
    my_dict[key+"-1"] = my_dict[key]-1

nó sẽ tạo ra lỗi thời gian chạy vì bạn đang thay đổi các phím trong khi chương trình đang chạy. Nếu bạn hoàn toàn được thiết lập để giảm thời gian, hãy sử dụng for key in my_dictcách, nhưng bạn đã được cảnh báo;).


2

Điều này sẽ in đầu ra theo thứ tự Sắp xếp theo Giá trị theo thứ tự tăng dần.

d = {'x': 3, 'y': 1, 'z': 2}
def by_value(item):
    return item[1]

for key, value in sorted(d.items(), key=by_value):
    print(key, '->', value)

Đầu ra:

nhập mô tả hình ảnh ở đây

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.