Mengurai kamus menggunakan loop 'untuk'

3139

Saya agak bingung dengan kode berikut:

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

Yang tidak saya mengerti adalah keyporsinya. Bagaimana Python mengenali bahwa itu hanya perlu membaca kunci dari kamus? Apakah keyada kata khusus dalam Python? Atau itu hanya variabel?

TopChef
sumber
4
Sebelum Anda memposting jawaban baru, pertimbangkan sudah ada 10+ jawaban untuk pertanyaan ini. Harap pastikan bahwa jawaban Anda menyumbangkan informasi yang tidak ada di antara jawaban yang ada.
janniks

Jawaban:

5394

key hanya nama variabel.

for key in d:

hanya akan mengulangi kunci dalam kamus, bukan kunci dan nilai. Untuk mengulangi kedua kunci dan nilai Anda dapat menggunakan yang berikut:

Untuk Python 3.x:

for key, value in d.items():

Untuk Python 2.x:

for key, value in d.iteritems():

Untuk menguji sendiri, ubah kata keymenjadi poop.

Dalam Python 3.x, iteritems()diganti dengan sederhana items(), yang mengembalikan tampilan seperti set yang didukung oleh dikt, seperti iteritems()tetapi lebih baik. Ini juga tersedia dalam 2,7 sebagai viewitems().

Operasi items()akan bekerja untuk 2 dan 3, tetapi di 2 akan mengembalikan daftar (key, value)pasangan kamus , yang tidak akan mencerminkan perubahan pada dikt yang terjadi setelah items()panggilan. Jika Anda menginginkan perilaku 2.x dalam 3.x, Anda dapat menelepon list(d.items()).

sberry
sumber
158
Menambahkan alasan yang diabaikan untuk tidak mengakses nilai seperti ini: d [kunci] di dalam for loop menyebabkan kunci di hash lagi (untuk mendapatkan nilai). Saat kamus besar, hash tambahan ini akan menambah waktu keseluruhan. Ini dibahas dalam pembicaraan teknis Raymond Hettinger, youtube.com/watch?v=anrOzOapJ2E
quiet_penguin
27
Mungkin masuk akal untuk menyebutkan bahwa barang akan diulang dalam urutan yang tidak terduga dan sorteddiperlukan untuk menstabilkannya.
yugr
5
@HarisankarKrishnaSwamy apa alternatifnya?
JoeyC
3
@Yugr Mengapa Anda mengatakan itu? Docs mengatakan Keys and values are iterated over in insertion order. [ docs.python.org/3/library/…
Geza Turi
4
@yugr Dari Python 3.7, kamus disusun berdasarkan urutan dan ini adalah fitur bahasa. Lihat stackoverflow.com/a/39980744/9428564
Aimery
433

Bukan itu kuncinya adalah kata khusus, tetapi kamus mengimplementasikan protokol iterator. Anda dapat melakukan ini di kelas Anda, mis. Lihat pertanyaan ini untuk bagaimana membangun iterator kelas.

Dalam kasus kamus, ini diimplementasikan pada tingkat C. Rinciannya tersedia di PEP 234 . Secara khusus, bagian berjudul "Kamus Kamus":

  • Kamus menerapkan slot tp_iter yang mengembalikan iterator efisien yang diulangi di atas kunci kamus. [...] Ini artinya kita bisa menulis

    for k in dict: ...

    yang setara dengan, tetapi jauh lebih cepat daripada

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

    selama pembatasan modifikasi kamus (baik oleh loop atau oleh utas lain) tidak dilanggar.

  • Tambahkan metode ke kamus yang mengembalikan berbagai jenis iterator secara eksplisit:

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

    Ini artinya for x in dictadalah singkatan for x in dict.iterkeys().

Dalam Python 3 dict.iterkeys(),, dict.itervalues()dan dict.iteritems()tidak lagi didukung. Gunakan dict.keys(), dict.values()dan dict.items()sebagai gantinya.

ars
sumber
207

Iterasi melalui dictiterasi melalui kuncinya tanpa urutan tertentu, seperti yang Anda lihat di sini:

Sunting: (Ini bukan lagi kasus di Python3.6 , tetapi perhatikan bahwa itu belum dijamin perilaku)

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

Sebagai contoh Anda, ini adalah ide yang lebih baik untuk digunakan dict.items():

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

Ini memberi Anda daftar tupel. Ketika Anda mengulanginya seperti ini, setiap tuple dibongkar kdan vsecara otomatis:

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

Menggunakan kdan vsebagai nama variabel saat perulangan di atas dictsangat umum jika badan perulangan hanya beberapa baris. Untuk loop yang lebih rumit, sebaiknya gunakan nama yang lebih deskriptif:

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

Sebaiknya biasakan menggunakan string format:

for letter, number in d.items():
    print('{0} corresponds to {1}'.format(letter, number))
John La Rooy
sumber
11
Dari catatan rilis Python 3.7: "Sifat pelestarian penyisipan-urutan objek dikt sekarang menjadi bagian resmi dari spesifikasi bahasa Python."
Gregory Arenius
86

key hanyalah sebuah variabel.

Untuk Python2.X :

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

... atau lebih baik,

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

Untuk Python3.X :

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

Ketika Anda beralih melalui kamus menggunakan for .. in ..-syntax, itu selalu berulang di atas kunci (nilai-nilai dapat diakses menggunakan dictionary[key]).

Untuk beralih dari pasangan nilai kunci, dalam Python 2 gunakan for k,v in s.iteritems(), dan dalam Python 3 for k,v in s.items().

Alexander Gessler
sumber
38
Perhatikan bahwa untuk Python 3, itu items()bukaniteritems()
Andreas Fester
19

Mengurai kamus menggunakan loop 'untuk'

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

Bagaimana Python mengenali bahwa itu hanya perlu membaca kunci dari kamus? Apakah kunci kata khusus dengan Python? Atau itu hanya variabel?

Ini bukan hanya forloop. Kata penting di sini adalah "iterasi".

Kamus adalah pemetaan kunci nilai:

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

Setiap kali kita beralih di atasnya, kita beralih di atas kunci. Nama variabel keyhanya dimaksudkan untuk deskriptif - dan itu cukup tepat untuk tujuan tersebut.

Ini terjadi dalam pemahaman daftar:

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

Ini terjadi ketika kami meneruskan kamus ke daftar (atau objek jenis koleksi lainnya):

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

Cara Python mengulangi adalah, dalam konteks di mana ia perlu, ia memanggil __iter__metode objek (dalam hal ini kamus) yang mengembalikan iterator (dalam hal ini, objek keyiterator):

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

Kita tidak harus menggunakan metode khusus ini diri kita sendiri, sebagai gantinya, gunakan fungsi builtin masing-masing untuk menyebutnya, iter:

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

Iterators memiliki __next__metode - tapi kami menyebutnya dengan fungsi builtin, 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

Ketika sebuah iterator habis, ia muncul StopIteration. Ini adalah cara Python tahu untuk keluar dari forloop, atau daftar pemahaman, atau ekspresi generator, atau konteks berulang lainnya. Setelah iterator memunculkannya, iterator StopIterationakan selalu memunculkannya - jika Anda ingin mengulanginya lagi, Anda perlu yang baru.

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

Kembali ke dikte

Kami telah melihat dikte yang berulang dalam banyak konteks. Apa yang telah kita lihat adalah bahwa setiap kali kita beralih pada dikt, kita mendapatkan kuncinya. Kembali ke contoh aslinya:

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

Jika kami mengubah nama variabel, kami masih mendapatkan kunci. Mari kita coba:

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

Jika kita ingin iterate atas nilai, kita perlu menggunakan .valuesmetode dicts, atau keduanya bersama-sama, .items:

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

Dalam contoh yang diberikan, akan lebih efisien untuk beralih ke item-item seperti ini:

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

Tetapi untuk tujuan akademis, contoh pertanyaan itu baik-baik saja.

Aaron Hall
sumber
17

Saya memiliki use case di mana saya harus beralih melalui dict untuk mendapatkan pasangan kunci, nilai, juga indeks yang menunjukkan di mana saya berada. Beginilah cara saya melakukannya:

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

Perhatikan bahwa tanda kurung di sekitar kunci, nilainya penting, tanpa tanda kurung, Anda mendapatkan ValueError "nilai tidak cukup untuk dibuka".

jdhao
sumber
1
Bagaimana ini relevan dengan pertanyaan?
jorijnsmit
8

Anda dapat memeriksa implementasi CPython dicttypedi GitHub. Ini adalah tanda tangan dari metode yang mengimplementasikan diktator iterator:

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

CPython dictobject.c

Ankur Agarwal
sumber
4

Untuk beralih lebih dari kunci, lebih lambat tetapi lebih baik digunakan my_dict.keys(). Jika Anda mencoba melakukan sesuatu seperti ini:

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

itu akan membuat kesalahan runtime karena Anda mengubah kunci saat program sedang berjalan. Jika Anda benar-benar ingin mengurangi waktu, gunakan for key in my_dictcaranya, tetapi Anda telah diperingatkan;).

Neil Chowdhury o_O
sumber
2

Ini akan mencetak output dalam urutan Diurutkan berdasarkan Nilai dalam urutan menaik.

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)

Keluaran:

masukkan deskripsi gambar di sini

Amar Kumar
sumber