Bagaimana mengembalikan kunci kamus sebagai daftar dengan Python?

783

Dalam Python 2.7 , saya bisa mendapatkan kunci kamus , nilai , atau item sebagai daftar:

>>> newdict = {1:0, 2:0, 3:0}
>>> newdict.keys()
[1, 2, 3]

Sekarang, dengan Python> = 3.3 , saya mendapatkan sesuatu seperti ini:

>>> newdict.keys()
dict_keys([1, 2, 3])

Jadi, saya harus melakukan ini untuk mendapatkan daftar:

newlist = list()
for i in newdict.keys():
    newlist.append(i)

Saya bertanya-tanya, apakah ada cara yang lebih baik untuk mengembalikan daftar dengan Python 3 ?

Dimitris Fasarakis Hilliard
sumber
Masalah keamanan utas yang menarik mengenai topik ini ada di sini: blog.labix.org/2008/06/27/…
Paul
2
Saya baru mengenal Python, dan bagi saya sepertinya proliferasi tipe data baru yang tidak berguna ini adalah salah satu aspek terburuk dari Python. Apa gunanya datatype dict_keys ini? Kenapa tidak daftar?
Phil Goetz

Jawaban:

977

Coba list(newdict.keys()).

Ini akan mengonversi dict_keysobjek ke daftar.

Di sisi lain, Anda harus bertanya pada diri sendiri apakah itu penting atau tidak. Cara Pythonic untuk kode adalah dengan mengasumsikan mengetik bebek ( jika terlihat seperti bebek dan dukun seperti bebek, itu bebek ). The dict_keysobjek akan bertindak seperti daftar untuk sebagian besar tujuan. Contohnya:

for key in newdict.keys():
  print(key)

Jelas, operator penyisipan mungkin tidak berfungsi, tetapi itu tidak masuk akal untuk daftar kunci kamus.

Chris
sumber
49
newdict.keys () tidak mendukung pengindeksan
gypaetus
57
list(newdict)juga berfungsi (setidaknya dalam python 3.4). Apakah ada alasan untuk menggunakan .keys()metode ini?
naught101
46
Catatan: dalam debugger pdb> list(newdict.keys()) gagal karena berbenturan dengan perintah pdb dengan nama yang sama. Gunakan pdb> !list(newdict.keys())untuk menghindari perintah pdb.
Riaz Rizvi
24
@ naught101 Ya, .keys()jauh lebih jelas tentang apa yang terjadi.
Felix D.
2
Perhatikan bahwa jika Anda menggunakan daftar (newdict.keys ()) bahwa kunci tidak dalam urutan yang Anda tempatkan karena urutan hashing!
Nate M
278

Python> = 3,5 alternatif: buka paket ke daftar literal [*newdict]

Generalisasi unpacking baru (PEP 448) diperkenalkan dengan Python 3.5 yang memungkinkan Anda sekarang dengan mudah melakukannya:

>>> newdict = {1:0, 2:0, 3:0}
>>> [*newdict]
[1, 2, 3]

Membongkar dengan *karya dengan objek apa pun yang dapat diubah dan, karena kamus mengembalikan kunci mereka saat diulangi, Anda dapat dengan mudah membuat daftar dengan menggunakannya dalam daftar literal.

Menambahkan .keys()mis. [*newdict.keys()]Mungkin membantu dalam membuat maksud Anda sedikit lebih eksplisit meskipun itu akan membebani Anda fungsi pencarian dan doa. (yang, dalam semua kejujuran, bukan sesuatu yang harus benar-benar khawatir tentang).

The *iterablesintaks mirip dengan melakukan list(iterable)dan perilakunya awalnya didokumentasikan dalam bagian Panggilan dari manual Python Referensi. Dengan PEP 448 pembatasan di mana *iterablebisa muncul dilonggarkan memungkinkan untuk juga ditempatkan dalam daftar, set dan tuple literal, manual referensi pada daftar Ekspresi juga diperbarui untuk menyatakan ini.


Meskipun setara list(newdict)dengan perbedaan yang lebih cepat (setidaknya untuk kamus kecil) karena tidak ada pemanggilan fungsi yang benar-benar dilakukan:

%timeit [*newdict]
1000000 loops, best of 3: 249 ns per loop

%timeit list(newdict)
1000000 loops, best of 3: 508 ns per loop

%timeit [k for k in newdict]
1000000 loops, best of 3: 574 ns per loop

dengan kamus yang lebih besar kecepatannya hampir sama (overhead iterasi melalui koleksi besar mengalahkan biaya panggilan fungsi yang kecil).


Dengan cara yang sama, Anda dapat membuat tupel dan set kunci kamus:

>>> *newdict,
(1, 2, 3)
>>> {*newdict}
{1, 2, 3}

Waspadalah terhadap koma yang tertinggal di kotak tuple!

Dimitris Fasarakis Hilliard
sumber
penjelasan besar, tapi tolong dapat Anda lihat link yang menjelaskan ini "* newdict" jenis sintaks, maksud saya bagaimana dan mengapa hasil ini kunci dari kamus hanya untuk understanding.Thanx
Muhammad Younus
1
@MYounas Sintaks itu telah tersedia untuk beberapa waktu, bahkan dalam Python 2. Dalam panggilan fungsi Anda dapat melakukan def foo(*args): print(args)diikuti foo(*{1:0, 2:0})dengan hasil yang (1, 2)sedang dicetak. Perilaku ini ditentukan di bagian Panggilan dalam manual referensi. Python 3.5 dengan PEP 448 hanya melonggarkan pembatasan di mana ini dapat muncul memungkinkan [*{1:0, 2:0}]untuk sekarang digunakan. Either way, saya akan mengedit jawaban saya dan memasukkan ini.
Dimitris Fasarakis Hilliard
1
*newdict- ini jelas merupakan jawaban untuk pegolf kode; P. Juga: yang, dalam semua kejujuran, bukan sesuatu yang harus Anda khawatirkan - dan jika ya, jangan gunakan python .
Artemis masih tidak percaya pada
46

list(newdict)bekerja di kedua Python 2 dan Python 3, memberikan daftar kunci sederhana di newdict. keys()tidak perlu. (:

Seb
sumber
26

Sedikit tentang definisi "mengetik bebek" - dict.keys()mengembalikan objek iterable, bukan objek seperti daftar. Ini akan bekerja di mana saja iterable akan bekerja - tidak ada tempat daftar akan. daftar juga merupakan iterable, tetapi iterable BUKAN daftar (atau urutan ...)

Dalam kasus penggunaan nyata, hal yang paling umum dilakukan dengan kunci dalam dikte adalah untuk beralih melalui mereka, jadi ini masuk akal. Dan jika Anda membutuhkannya sebagai daftar, Anda dapat menelepon list().

Sangat mirip untuk zip()- dalam sebagian besar kasus, iterasi melalui - mengapa membuat daftar tuple baru hanya untuk beralih melalui itu dan kemudian membuangnya lagi?

Ini adalah bagian dari tren besar dalam python untuk menggunakan lebih banyak iterator (dan generator), daripada salinan daftar di semua tempat.

dict.keys() harus bekerja dengan pemahaman, meskipun - periksa dengan teliti untuk kesalahan ketik atau sesuatu ... itu berfungsi dengan baik untuk saya:

>>> d = dict(zip(['Sounder V Depth, F', 'Vessel Latitude, Degrees-Minutes'], [None, None]))
>>> [key.split(", ") for key in d.keys()]
[['Sounder V Depth', 'F'], ['Vessel Latitude', 'Degrees-Minutes']]
Chris Barker
sumber
2
Anda bahkan tidak perlu menggunakan .keys(); obyek kamus itu sendiri iterable dan menghasilkan kunci ketika iterasi berakhir: [key.split(", ") for key in d].
Martijn Pieters
25

Anda juga dapat menggunakan pemahaman daftar :

>>> newdict = {1:0, 2:0, 3:0}
>>> [k  for  k in  newdict.keys()]
[1, 2, 3]

Atau, lebih pendek,

>>> [k  for  k in  newdict]
[1, 2, 3]

Catatan: Pesanan tidak dijamin pada versi di bawah 3.7 (pemesanan masih hanya detail implementasi dengan CPython 3.6).

未来 陆家嘴 顶尖 的 投资 人
sumber
6
Gunakan saja list(newdict). Tidak perlu untuk memahami daftar di sini.
Martijn Pieters
8

Konversi ke daftar tanpa menggunakan keysmetode membuatnya lebih mudah dibaca:

list(newdict)

dan, ketika menggunakan kamus, tidak perlu keys():

for key in newdict:
    print key

kecuali Anda memodifikasinya dalam loop yang akan membutuhkan daftar kunci yang dibuat sebelumnya:

for key in list(newdict):
    del newdict[key]

Di Python 2 ada keuntungan kinerja marjinal menggunakankeys() .

Cas
sumber
8

Jika Anda perlu menyimpan kunci secara terpisah, inilah solusi yang membutuhkan pengetikan lebih sedikit daripada setiap solusi lain yang disajikan sejauh ini, menggunakan Extended Iterable Unpacking (python3.x +).

newdict = {1: 0, 2: 0, 3: 0}
*k, = newdict

k
# [1, 2, 3]

            ╒═══════════════╤═════════════════════════════════════════╕
             k = list(d)      9 characters (excluding whitespace)   
            ├───────────────┼─────────────────────────────────────────┤
             k = [*d]         6 characters                          
            ├───────────────┼─────────────────────────────────────────┤
             *k, = d          5 characters                          
            ╘═══════════════╧═════════════════════════════════════════╛
cs95
sumber
1
Satu-satunya peringatan kecil yang saya tunjukkan kadalah selalu ada daftar di sini. Jika pengguna menginginkan tuple atau set dari tombol, mereka harus kembali ke opsi lain.
Dimitris Fasarakis Hilliard
1
Catatan yang lebih penting adalah fakta bahwa, sebagai sebuah pernyataan, *k, = dmemiliki batasan di mana ia dapat muncul (tapi lihat, dan mungkin perbarui jawaban ini untuk, PEP 572 - pembongkaran yang diperluas tidak didukung untuk penugasan ekspresi atm tetapi mungkin suatu hari nanti! )
Dimitris Fasarakis Hilliard
bagaimana jika Anda ingin kedua kunci dan nilai daftar?
endolith
1
@endolith mungkin keys, vals = zip(*d.items())(meskipun itu memberi dua tupel, cukup dekat). Saya tidak tahu ekspresi yang lebih pendek dari ini.
cs95
1

Saya dapat memikirkan 2 cara di mana kita dapat mengekstrak kunci dari kamus.

Metode 1: - Untuk mendapatkan kunci menggunakan metode .keys () dan kemudian mengonversinya menjadi daftar.

some_dict = {1: 'one', 2: 'two', 3: 'three'}
list_of_keys = list(some_dict.keys())
print(list_of_keys)
-->[1,2,3]

Metode 2: - Untuk membuat daftar kosong dan kemudian menambahkan kunci ke daftar melalui loop. Anda bisa mendapatkan nilai dengan loop ini juga (gunakan .keys () hanya untuk kunci dan .items () untuk ekstraksi kunci dan nilai)

list_of_keys = []
list_of_values = []
for key,val in some_dict.items():
    list_of_keys.append(key)
    list_of_values.append(val)

print(list_of_keys)
-->[1,2,3]

print(list_of_values)
-->['one','two','three']
Rahul
sumber