Saya agak bingung tentang apa yang bisa / tidak bisa digunakan sebagai kunci untuk python dict.
dicked = {}
dicked[None] = 'foo' # None ok
dicked[(1,3)] = 'baz' # tuple ok
import sys
dicked[sys] = 'bar' # wow, even a module is ok !
dicked[(1,[3])] = 'qux' # oops, not allowed
Jadi tuple adalah tipe yang tidak dapat diubah tetapi jika saya menyembunyikan daftar di dalamnya, maka itu tidak bisa menjadi kunci .. tidak bisakah saya dengan mudah menyembunyikan daftar di dalam modul?
Saya memiliki ide yang tidak jelas bahwa kuncinya harus "dapat di-hash" tetapi saya hanya akan mengakui ketidaktahuan saya sendiri tentang detail teknis; Saya tidak tahu apa yang sebenarnya terjadi di sini. Apa yang salah jika Anda mencoba menggunakan daftar sebagai kunci, dengan hash sebagai, katakanlah, lokasi memorinya?
Jawaban:
Ada artikel bagus tentang topik di wiki Python: Mengapa Daftar Tidak Bisa Menjadi Kunci Kamus . Seperti yang dijelaskan di sana:
Itu dapat dilakukan tanpa benar-benar melanggar persyaratan apa pun, tetapi itu mengarah pada perilaku yang tidak terduga. Daftar umumnya diperlakukan seolah-olah nilainya berasal dari nilai isinya, misalnya saat memeriksa persamaan (dalam-). Banyak yang akan - dapat dimengerti - berharap bahwa Anda dapat menggunakan daftar apa pun
[1, 2]
untuk mendapatkan kunci yang sama, di mana Anda harus menyimpan objek daftar yang persis sama. Tetapi pencarian menurut pemutusan nilai segera setelah daftar yang digunakan sebagai kunci diubah, dan untuk pencarian berdasarkan identitas mengharuskan Anda untuk menyimpan daftar yang persis sama - yang tidak memerlukan operasi daftar umum lainnya (setidaknya tidak ada yang dapat saya pikirkan ).Objek lain seperti modul dan
object
membuat kesepakatan yang jauh lebih besar dari identitas objek mereka (kapan terakhir kali Anda memiliki dua objek modul yang berbeda dipanggilsys
?), Dan tetap dibandingkan dengan itu. Oleh karena itu, kurang mengherankan - atau bahkan diharapkan - bahwa mereka, ketika digunakan sebagai kunci dict, dibandingkan dengan identitas dalam kasus itu juga.sumber
Mengapa saya tidak bisa menggunakan list sebagai kunci dict di python?
(untuk siapa saja yang tersandung pada pertanyaan ini mencari jalan keluarnya)
seperti yang dijelaskan oleh orang lain di sini, memang Anda tidak bisa. Namun Anda dapat menggunakan representasi stringnya jika Anda benar-benar ingin menggunakan daftar Anda.
sumber
__eq__
. Tetapi jika Anda mengubahnya menjadi string, semuanya dibandingkan dengan representasi stringnya.Baru ditemukan Anda dapat mengubah Daftar menjadi tupel, lalu menggunakannya sebagai kunci.
sumber
Masalahnya adalah bahwa tupel tidak dapat diubah, dan daftar tidak. Simak berikut ini
Apa yang harus
d[li]
dikembalikan? Apakah ini daftar yang sama? Bagaimana dengand[[1,2,3]]
? Ini memiliki nilai yang sama, tetapi apakah daftarnya berbeda?Pada akhirnya, tidak ada jawaban yang memuaskan. Misalnya, jika satu-satunya kunci yang berfungsi adalah kunci asli, maka jika Anda tidak memiliki referensi ke kunci tersebut, Anda tidak dapat lagi mengakses nilainya. Dengan setiap kunci lain yang diizinkan, Anda dapat membuat kunci tanpa referensi ke aslinya.
Jika kedua saran saya berfungsi, maka Anda memiliki kunci yang sangat berbeda yang mengembalikan nilai yang sama, yang lebih dari sedikit mengejutkan. Jika hanya konten asli yang berfungsi, maka kunci Anda akan segera rusak, karena daftar dibuat untuk dimodifikasi.
sumber
d[li]
untuk tetap 5.d[[1,2,3]]
akan merujuk ke objek daftar yang berbeda sebagai kunci, jadi itu akan menjadi sebuah KeyError. Saya belum benar-benar melihat masalah apa pun .. kecuali bahwa membiarkan kunci mengumpulkan sampah mungkin membuat beberapa nilai dict tidak dapat diakses. Tapi itu masalah praktis bukan masalah logis ..d[list(li)]
menjadi KeyError adalah bagian dari masalah. Dalam hampir setiap kasus penggunaan lainnya ,li
tidak dapat dibedakan dari daftar baru dengan konten yang identik. Ini berfungsi, tetapi kontra-intuitif bagi banyak orang. Plus, kapan terakhir kali Anda benar-benar harus menggunakan list sebagai kunci dict? Satu-satunya kasus penggunaan yang dapat saya bayangkan adalah ketika Anda meng-hashing semuanya berdasarkan identitas, dan dalam kasus itu Anda harus melakukannya alih-alih mengandalkan__hash__
dan__eq__
menjadi berbasis identitas.Inilah jawabannya http://wiki.python.org/moin/DictionaryKeys
Mencari daftar yang berbeda dengan konten yang sama akan menghasilkan hasil yang berbeda, meskipun membandingkan daftar dengan konten yang sama akan menunjukkan bahwa mereka setara.
Bagaimana dengan Menggunakan literal daftar dalam pencarian kamus?
sumber
Karena daftar dapat berubah,
dict
kunci (danset
anggota) harus dapat dicirikan, dan mencirikan objek yang dapat berubah adalah ide yang buruk karena nilai hash harus dihitung berdasarkan atribut instance.Pada jawaban ini, saya akan memberikan beberapa contoh konkret, semoga menambah nilai di atas jawaban yang ada. Setiap wawasan berlaku untuk elemen struktur data
set
juga.Contoh 1 : hashing objek yang bisa berubah di mana nilai hash didasarkan pada karakteristik objek yang bisa berubah.
Setelah bermutasi
stupid
, itu tidak dapat ditemukan lagi di dict karena hash berubah. Hanya pemindaian linier atas daftar kunci dict yang ditemukanstupid
.Contoh 2 : ... tetapi mengapa tidak hanya nilai hash konstan?
Itu juga bukan ide yang bagus karena objek yang sama harus memiliki hash yang identik sehingga Anda dapat menemukannya di a
dict
atauset
.Contoh 3 : ... ok, bagaimana dengan hash konstan di semua instance ?!
Hal-hal tampaknya berfungsi seperti yang diharapkan, tetapi pikirkan tentang apa yang terjadi: ketika semua instance kelas Anda menghasilkan nilai hash yang sama, Anda akan mengalami benturan hash setiap kali ada lebih dari dua instance sebagai kunci dalam a
dict
atau hadir di aset
.Menemukan instance yang tepat dengan
my_dict[key]
ataukey in my_dict
(atauitem in my_set
) perlu melakukan sebanyak mungkin pemeriksaan kesetaraan karena ada instancestupidlist3
di kunci dict (dalam kasus terburuk). Pada titik ini, tujuan pencarian kamus - O (1) - benar-benar dikalahkan. Ini ditunjukkan dalam pengaturan waktu berikut (dilakukan dengan IPython).Beberapa Waktu untuk Contoh 3
Seperti yang Anda lihat, uji keanggotaan di kami
stupidlists_set
bahkan lebih lambat daripada pemindaian linier secara keseluruhanlists_list
, sementara Anda memiliki waktu pencarian super cepat yang diharapkan (faktor 500) dalam satu set tanpa banyak benturan hash.TL; DR: Anda dapat menggunakan
tuple(yourlist)
sebagaidict
kunci, karena tupel tidak dapat diubah dan memiliki hash.sumber
x
danz
sama. Jika ada sesuatu tentang itu yang tidak jelas, silakan buka pertanyaan baru.hash(x)
danhash(z)
.Awnser Anda dapat ditemukan di sini:
Sumber & info lebih lanjut: http://wiki.python.org/moin/DictionaryKeys
sumber
Jawaban sederhana untuk pertanyaan Anda adalah bahwa daftar kelas tidak mengimplementasikan hash metode yang diperlukan untuk objek apa pun yang ingin digunakan sebagai kunci dalam kamus. Namun alasan mengapa hash tidak diimplementasikan dengan cara yang sama seperti yang dikatakan kelas tuple (berdasarkan konten wadah) adalah karena daftar bisa berubah sehingga mengedit daftar akan membutuhkan hash untuk dihitung ulang yang mungkin berarti daftar di sekarang terletak di keranjang yang salah dalam tabel hash bawahan. Perhatikan bahwa karena Anda tidak dapat memodifikasi tupel (tidak dapat diubah), ini tidak mengalami masalah ini.
Sebagai catatan tambahan, implementasi aktual dari pencarian dictobjects didasarkan pada Algoritma D dari Knuth Vol. 3, Detik. 6.4. Jika Anda memiliki buku itu yang tersedia untuk Anda, mungkin itu adalah bacaan yang berharga, selain itu jika Anda benar-benar tertarik, Anda mungkin ingin mengintip komentar pengembang tentang implementasi sebenarnya dari diktobyek di sini. Ini menjadi sangat rinci tentang cara kerjanya. Ada juga kuliah python tentang implementasi kamus yang mungkin Anda minati. Mereka membahas definisi kunci dan apa itu hash dalam beberapa menit pertama.
sumber
Menurut dokumentasi Python 2.7.2:
Tupel tidak dapat diubah dalam arti bahwa Anda tidak dapat menambah, menghapus, atau mengganti elemennya, tetapi elemen itu sendiri dapat berubah. Nilai hash daftar bergantung pada nilai hash elemennya, dan karenanya berubah saat Anda mengubah elemen.
Menggunakan id untuk hash daftar akan menyiratkan bahwa semua daftar dibandingkan secara berbeda, yang akan mengejutkan dan tidak nyaman.
sumber
hash = id
tidak merusak invarian di akhir paragraf pertama, pertanyaannya adalah mengapa tidak dilakukan seperti itu.sesuatu seperti (kode psuedo):
Jika Anda bertanya-tanya opsi mana yang tersedia yang dapat digunakan sebagai kunci untuk kamus Anda. Kemudian
Anda dapat mencoba :
Jika berfungsi dengan baik, itu dapat digunakan sebagai kunci untuk kamus Anda atau mengubahnya menjadi sesuatu yang dapat hash.
Pendeknya :
tuple(<your list>)
.str(<your list>)
.sumber
dict
kunci harus dapat di-hash. Daftar Dapat Diubah dan tidak menyediakan metode hash yang valid .sumber