Mengapa dict.get (key) alih-alih dict [key]?

651

Hari ini, saya menemukan dictmetode getyang, diberikan kunci dalam kamus, mengembalikan nilai yang terkait.

Untuk tujuan apa fungsi ini berguna? Jika saya ingin menemukan nilai yang terkait dengan kunci dalam kamus, saya bisa melakukannya dict[key], dan mengembalikan hal yang sama:

dictionary = {"Name": "Harry", "Age": 17}
dictionary["Name"]
dictionary.get("Name")
stensootla
sumber
1
dictionary["foo"]dan dictionary.get("foo")berperilaku berbeda.
Niklas B.
34
dictionary.get("Age") sama dengan menulis dictionary["Age"] or None sehingga secara implisit menangani pengecualian KeyError
yosemite_k
5
@yosemite_k Saya mungkin kehilangan beberapa konteks di sini, tetapi dictionary['non-existent key'] or Noneharus dan masih meningkatkan KeyErroruntuk saya (hingga v3.6). Bisakah Anda menjelaskan maksud Anda?
nivk
Kamus @nivk ['kunci tidak ada'] memunculkan kesalahan, dan kesalahan itu harus ditangani secara eksplisit. jika sebaliknya Anda menggunakan dictionary.get () (yang secara harfiah berfungsi sebagai kamus ['kunci tidak ada'] atau Tidak Ada) pengecualian itu ditangani secara implisit.
yosemite_k

Jawaban:

993

Ini memungkinkan Anda untuk memberikan nilai default jika kunci tidak ada:

dictionary.get("bogus", default_value)

mengembalikan default_value(apa pun yang Anda pilih), sedangkan

dictionary["bogus"]

akan menaikkan KeyError.

Jika dihilangkan, default_valueadalah Nonesedemikian rupa

dictionary.get("bogus")  # <-- No default specified -- defaults to None

kembali Nonesama seperti

dictionary.get("bogus", None)

akan.

unutbu
sumber
1
Apakah ini sama dengan dictionary.get("bogus") or my_default? Saya telah melihat orang menggunakannya dalam beberapa kasus dan saya bertanya-tanya apakah ada keuntungan menggunakan salah satu daripada yang lain (selain keterbacaan)
Algoritma
15
@MustafaS: Jika "bogus"adalah kunci dalam dictionarydan dictionary.get("bogus")pengembalian nilai yang mengevaluasi ke False dalam konteks boolean (yaitu nilai Falsey), seperti 0 atau string kosong, ''maka dictionary.get("bogus") or my_defaultakan mengevaluasi my_defaultsedangkan dictionary.get("bogus", my_default)akan kembali nilai Falsey. Jadi tidak, dictionary.get("bogus") or my_defaulttidak setara dengan dictionary.get("bogus", my_default). Yang digunakan tergantung pada perilaku yang Anda inginkan.
unutbu
3
@Ustafa: Sebagai contoh, misalkan x = {'a':0}. Kemudian x.get('a', 'foo')kembali 0tetapi x.get('a') or 'foo'kembali 'foo'.
unutbu
3
Satu kemungkinan peringatan ketika menggunakan dictionary.get('key'): Ini bisa membingungkan jika nilai dalam kamus None. Tanpa menentukan nilai kembali (argumen opsional kedua) tidak ada cara untuk memverifikasi jika kunci tidak ada atau jika nilainya None. Dalam kasus khusus ini saya akan mempertimbangkan menggunakan try-except-KeyError.
Aart Goossens
1
Perlu dicatat bahwa ekspresi untuk menentukan nilai default dievaluasi dalam panggilan "dapatkan", dan karenanya dievaluasi pada setiap akses. Alternatif klasik (menggunakan pengendali KeyError atau predikat) adalah mengevaluasi nilai default hanya jika kunci tidak ada. Ini memungkinkan closure / lambda dibuat sekali dan dievaluasi pada kunci yang hilang.
Tom Stambaugh
142

Apa dict.get()metodenya?

Seperti telah disebutkan getmetode ini berisi parameter tambahan yang menunjukkan nilai yang hilang. Dari dokumentasi

get(key[, default])

Kembalikan nilai untuk kunci jika kunci ada di kamus, kalau tidak default. Jika default tidak diberikan, defaultnya adalah None, sehingga metode ini tidak pernah memunculkan a KeyError.

Contohnya bisa

>>> d = {1:2,2:3}
>>> d[1]
2
>>> d.get(1)
2
>>> d.get(3)
>>> repr(d.get(3))
'None'
>>> d.get(3,1)
1

Apakah ada peningkatan kecepatan di mana saja?

Seperti yang disebutkan di sini ,

Tampaknya ketiga pendekatan sekarang menunjukkan kinerja yang sama (sekitar 10% dari satu sama lain), lebih atau kurang independen dari sifat daftar kata.

Sebelumnya getjauh lebih lambat, Namun sekarang kecepatannya hampir sebanding dengan keuntungan tambahan mengembalikan nilai default. Tetapi untuk menghapus semua pertanyaan kami, kami dapat menguji pada daftar yang cukup besar (Perhatikan bahwa tes ini mencakup mencari semua kunci yang valid saja)

def getway(d):
    for i in range(100):
        s = d.get(i)

def lookup(d):
    for i in range(100):
        s = d[i]

Sekarang pengaturan waktu kedua fungsi ini menggunakan timeit

>>> import timeit
>>> print(timeit.timeit("getway({i:i for i in range(100)})","from __main__ import getway"))
20.2124660015
>>> print(timeit.timeit("lookup({i:i for i in range(100)})","from __main__ import lookup"))
16.16223979

Seperti yang bisa kita lihat, pencarian lebih cepat daripada pencarian karena tidak ada fungsi pencarian. Ini bisa dilihat melaluidis

>>> def lookup(d,val):
...     return d[val]
... 
>>> def getway(d,val):
...     return d.get(val)
... 
>>> dis.dis(getway)
  2           0 LOAD_FAST                0 (d)
              3 LOAD_ATTR                0 (get)
              6 LOAD_FAST                1 (val)
              9 CALL_FUNCTION            1
             12 RETURN_VALUE        
>>> dis.dis(lookup)
  2           0 LOAD_FAST                0 (d)
              3 LOAD_FAST                1 (val)
              6 BINARY_SUBSCR       
              7 RETURN_VALUE  

Di mana itu akan berguna?

Ini akan berguna setiap kali Anda ingin memberikan nilai default setiap kali Anda mencari kamus. Ini mengurangi

 if key in dic:
      val = dic[key]
 else:
      val = def_val

Untuk satu baris, val = dic.get(key,def_val)

Di mana itu TIDAK berguna?

Setiap kali Anda ingin mengembalikan KeyErrorpernyataan bahwa kunci tertentu tidak tersedia. Mengembalikan nilai default juga membawa risiko bahwa nilai default tertentu juga bisa menjadi kunci!

Apakah mungkin untuk memiliki getfitur serupa dict['key']?

Iya! Kita perlu mengimplementasikan __missing__subclass dict.

Contoh program bisa

class MyDict(dict):
    def __missing__(self, key):
        return None

Demonstrasi kecil bisa

>>> my_d = MyDict({1:2,2:3})
>>> my_d[1]
2
>>> my_d[3]
>>> repr(my_d[3])
'None'
Bhargav Rao
sumber
32
Standar emas jawaban StackOverflow!
Apollo Data
1
Satu tes yang baik lebih akan menjadi if k in dict and dict[k]:vs if dict.get(k):. Ini mencakup situasi ketika kita perlu memeriksa apakah kunci ada, dan jika 'ya' - apa nilai ?, sesuatu seperti: dict = {1: '', 2: 'some value'}.
TitanFighter
7
Harap ingat bahwa nilai default akan dievaluasi terlepas dari nilai yang ada di kamus, jadi alih-alih dictionary.get(value, long_function())orang dapat mempertimbangkan untuk menggunakandictionary.get(value) or long_function()
Kresimir
Ah @Kresimir, benar. Saya memang mendapatkan pertanyaan itu dalam salah satu wawancara yang saya hadapi (saya tidak tahu tentang hal itu ketika saya awalnya memposting jawaban ini). Terima kasih telah mengingatkan saya tentang hal itu.
Bhargav Rao
32

getmengambil nilai opsional kedua. Jika kunci yang ditentukan tidak ada dalam kamus Anda, maka nilai ini akan dikembalikan.

dictionary = {"Name": "Harry", "Age": 17}
dictionary.get('Year', 'No available data')
>> 'No available data'

Jika Anda tidak memberikan parameter kedua, Noneakan dikembalikan.

Jika Anda menggunakan pengindeksan seperti pada dictionary['Year'], kunci tidak ada akan naik KeyError.

FallenAngel
sumber
19

Saya akan memberikan contoh praktis dalam mengikis data web menggunakan python, banyak kali Anda akan mendapatkan kunci tanpa nilai, dalam kasus tersebut Anda akan mendapatkan kesalahan jika Anda menggunakan kamus ['kunci'], sedangkan kamus.get ('kunci ',' return_otherwise ') tidak punya masalah.

Demikian pula, saya akan menggunakan '' .join (daftar) sebagai lawan dari daftar [0] jika Anda mencoba untuk menangkap nilai tunggal dari daftar.

semoga membantu.

[Sunting] Ini adalah contoh praktis:

Katakanlah, Anda memanggil API, yang mengembalikan file JOSN yang Anda perlu parsing. JSON pertama terlihat seperti berikut:

{"bids":{"id":16210506,"submitdate":"2011-10-16 15:53:25","submitdate_f":"10\/16\/2011 at 21:53 CEST","submitdate_f2":"p\u0159ed 2 lety","submitdate_ts":1318794805,"users_id":"2674360","project_id":"1250499"}}

JOSN kedua adalah seperti ini:

{"bids":{"id":16210506,"submitdate":"2011-10-16 15:53:25","submitdate_f":"10\/16\/2011 at 21:53 CEST","submitdate_f2":"p\u0159ed 2 lety","users_id":"2674360","project_id":"1250499"}}

Perhatikan bahwa JSON kedua tidak memiliki kunci "submitdate_ts", yang cukup normal dalam struktur data apa pun.

Jadi ketika Anda mencoba mengakses nilai kunci itu dalam satu lingkaran, dapatkah Anda menyebutnya dengan yang berikut:

for item in API_call:
    submitdate_ts = item["bids"]["submitdate_ts"]

Anda bisa, tetapi itu akan memberi Anda kesalahan traceback untuk baris JSON kedua, karena kuncinya tidak ada.

Cara pengkodean yang tepat ini, bisa sebagai berikut:

for item in API_call:
    submitdate_ts = item.get("bids", {'x': None}).get("submitdate_ts")

{'x': Tidak Ada} ada untuk menghindari kesalahan tingkat kedua. Tentu saja Anda dapat membangun lebih banyak toleransi kesalahan ke dalam kode jika Anda melakukan pengikisan. Seperti pertama yang menentukan kondisi if

kevin
sumber
2
Sebuah jawaban yang baik, diposting sebelum yang lain, yang akan lebih ditingkatkan, dan mungkin diterima, jika Anda telah memposting beberapa contoh kode (+1 dari saya, meskipun)
Mawg mengatakan mengembalikan Monica
2
@ Mawg Saya baru-baru ini memiliki proyek memo untuk penelitian saya. Itu memanggil API dan parsing file JSON pada dasarnya. Saya meminta RA saya melakukannya. Salah satu masalah utama yang dia miliki adalah memanggil kunci secara langsung, ketika banyak kunci yang sebenarnya hilang. Saya akan memposting contoh dalam teks di atas.
kevin
terima kasih telah menangani aspek multi-dimensi ini! Kedengarannya Anda bahkan dapat melakukan {} alih-alih {'x': Tidak Ada}
bluppfisk
17

Tujuannya agar Anda dapat memberikan nilai default jika kunci tidak ditemukan, yang sangat berguna

dictionary.get("Name",'harry')
hackartist
sumber
8

Untuk tujuan apa fungsi ini berguna?

Salah satu penggunaan khusus menghitung dengan kamus. Misalkan Anda ingin menghitung jumlah kemunculan setiap elemen dalam daftar yang diberikan. Cara umum untuk melakukannya adalah membuat kamus di mana kunci adalah elemen dan nilai adalah jumlah kemunculannya.

fruits = ['apple', 'banana', 'peach', 'apple', 'pear']
d = {}
for fruit in fruits:
    if fruit not in d:
        d[fruit] = 0
    d[fruit] += 1

Dengan menggunakan .get()metode ini, Anda dapat membuat kode ini lebih ringkas dan jelas:

for fruit in fruits:
    d[fruit] = d.get(fruit, 0) + 1
jetpack_guy
sumber
7

Gotcha yang harus diperhatikan saat menggunakan .get():

Jika kamus berisi kunci yang digunakan dalam panggilan ke .get()dan nilainya adalah None, .get()metode akan kembali Nonebahkan jika nilai standar diberikan.

Misalnya, pengembalian berikut None, tidak 'alt_value'seperti yang diharapkan:

d = {'key': None}
d.get('key', 'alt_value')

.get()Nilai kedua hanya dikembalikan jika kunci yang disediakan TIDAK dalam kamus, bukan jika nilai balik panggilan itu None.

Colton Hicks
sumber
1
Yang ini membuat saya: \ Salah satu cara untuk menyelesaikan ini adalah memiliki d.get('key') or 'alt_value'jika Anda tahu itu mungkinNone
Daniel Holmes
4

Mengapa dict.get (key) alih-alih dict [key]?

0. Ringkasan

Dibandingkan dengan dict[key], dict.getmemberikan nilai mundur ketika mencari kunci.

1. Definisi

get (key [, default]) 4. Built-in Types - Dokumentasi Python 3.6.4rc1

Kembalikan nilai untuk kunci jika kunci ada di kamus, kalau tidak default. Jika default tidak diberikan, defaultnya adalah None, sehingga metode ini tidak pernah memunculkan KeyError.

d = {"Name": "Harry", "Age": 17}
In [4]: d['gender']
KeyError: 'gender'
In [5]: d.get('gender', 'Not specified, please add it')
Out[5]: 'Not specified, please add it'

2. Masalah itu terpecahkan.

Jika tanpa default value, Anda harus menulis kode rumit untuk menangani pengecualian seperti itu.

def get_harry_info(key):
    try:
        return "{}".format(d[key])
    except KeyError:
        return 'Not specified, please add it'
In [9]: get_harry_info('Name')
Out[9]: 'Harry'
In [10]: get_harry_info('Gender')
Out[10]: 'Not specified, please add it'

Sebagai solusi yang nyaman, dict.getmemperkenalkan nilai default opsional menghindari kode di atas tanpa disadari.

3. Kesimpulan

dict.get memiliki opsi nilai default tambahan untuk menangani pengecualian jika kunci tidak ada dalam kamus

Kalkulus
sumber
0

Satu perbedaan, yang bisa menjadi keuntungan, adalah bahwa jika kita mencari kunci yang tidak ada, kita akan mendapatkan Tidak ada, tidak seperti ketika kita menggunakan notasi tanda kurung, dalam hal ini kita akan mendapatkan kesalahan yang dilemparkan:

print(dictionary.get("address")) # None
print(dictionary["address"]) # throws KeyError: 'address'

Hal terakhir yang keren tentang metode get, adalah bahwa ia menerima argumen opsional tambahan untuk nilai default, yaitu jika kita mencoba untuk mendapatkan nilai skor dari seorang siswa, tetapi siswa tidak memiliki kunci skor yang bisa kita dapatkan a 0 sebagai gantinya.

Jadi alih-alih melakukan ini (atau yang serupa):

score = None
try:
    score = dictionary["score"]
except KeyError:
    score = 0

Kita bisa melakukan ini:

score = dictionary.get("score", 0)
# score = 0
אנונימי
sumber
-1

Berdasarkan penggunaan harus menggunakan getmetode ini .

Contoh 1

In [14]: user_dict = {'type': False}

In [15]: user_dict.get('type', '')

Out[15]: False

In [16]: user_dict.get('type') or ''

Out[16]: ''

Contoh2

In [17]: user_dict = {'type': "lead"}

In [18]: user_dict.get('type') or ''

Out[18]: 'lead'

In [19]: user_dict.get('type', '')

Out[19]: 'lead'
Muthuvel
sumber