ทำไม dict.get (กุญแจ) แทนที่จะเป็น dict [key]


649

วันนี้ฉันเจอdictวิธีgetที่ให้คีย์ในพจนานุกรมคืนค่าที่เกี่ยวข้อง

ฟังก์ชั่นนี้มีประโยชน์สำหรับวัตถุประสงค์ใด? หากฉันต้องการหาค่าที่เกี่ยวข้องกับคีย์ในพจนานุกรมฉันสามารถทำได้dict[key]และมันจะส่งคืนสิ่งเดียวกัน:

dictionary = {"Name": "Harry", "Age": 17}
dictionary["Name"]
dictionary.get("Name")

1
dictionary["foo"]และdictionary.get("foo")ทำตัวต่างออกไป
Niklas B.

34
dictionary.get("Age") เหมือนกับการเขียนdictionary["Age"] or None ดังนั้นจึงจัดการกับข้อยกเว้น KeyError โดยปริยาย
yosemite_k

5
@yosemite_k ฉันอาจจะพลาดบริบทบางอย่างที่นี่ แต่dictionary['non-existent key'] or Noneควรและควรเพิ่มKeyErrorสำหรับฉัน (มากถึง v3.6) คุณสามารถอธิบายสิ่งที่คุณหมายถึงอะไร
nivk

@nivk พจนานุกรม ['ไม่มีคีย์ที่มีอยู่'] ทำให้เกิดข้อผิดพลาดและข้อผิดพลาดนั้นควรได้รับการจัดการอย่างชัดเจน หากคุณใช้ dictionary.get () ซึ่งทำหน้าที่เป็นพจนานุกรม ['ไม่มีคีย์' หรือไม่มี) ให้จัดการข้อยกเว้นโดยปริยาย
yosemite_k

คำตอบ:


991

ช่วยให้คุณสามารถระบุค่าเริ่มต้นหากไม่มีคีย์:

dictionary.get("bogus", default_value)

ผลตอบแทนdefault_value(สิ่งที่คุณเลือกที่จะเป็น) ในขณะที่

dictionary["bogus"]

KeyErrorจะยก

หากไม่ได้ระบุไว้default_valueจะเป็นNoneเช่นนั้น

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

ผลตอบแทนNoneเช่นเดียวกับ

dictionary.get("bogus", None)

หากว่า


1
สิ่งนี้จะเหมือนกันdictionary.get("bogus") or my_defaultหรือไม่ ฉันเคยเห็นคนใช้มันในบางกรณีและฉันสงสัยว่ามีประโยชน์ในการใช้งานแทนการใช้อย่างอื่น (นอกเหนือจากการอ่าน)
Algorithmatic

15
@MustafaS: ถ้า"bogus"เป็นคีย์ในdictionaryและdictionary.get("bogus")ส่งคืนค่าซึ่งประเมินค่าเป็น False ในบริบทบูลีน (เช่นค่า Falsey) เช่น 0 หรือสตริงว่าง''ดังนั้นdictionary.get("bogus") or my_defaultจะประเมินค่าmy_defaultในขณะที่dictionary.get("bogus", my_default)จะส่งกลับค่า Falsey ดังนั้นไม่มีจะไม่เทียบเท่ากับdictionary.get("bogus") or my_default dictionary.get("bogus", my_default)สิ่งที่จะใช้ขึ้นอยู่กับพฤติกรรมที่คุณต้องการ
unutbu

3
@MustafaS: x = {'a':0}ตัวอย่างเช่นสมมติว่า แล้วx.get('a', 'foo')ผลตอบแทน0แต่ผลตอบแทนx.get('a') or 'foo' 'foo'
unutbu

3
caveat หนึ่งที่เป็นไปได้เมื่อใช้dictionary.get('key'): Noneมันสามารถทำให้เกิดความสับสนถ้าค่าในพจนานุกรมเป็น หากไม่มีการระบุค่าส่งคืน (อาร์กิวเมนต์ที่เป็นทางเลือกที่สอง) จะไม่มีวิธีการตรวจสอบว่าไม่มีรหัสหรือไม่มีค่าNoneหรือไม่ try-except-KeyErrorในกรณีนี้โดยเฉพาะผมจะพิจารณาใช้
Aart Goossens

1
เป็นที่น่าสังเกตว่านิพจน์เพื่อระบุค่าเริ่มต้นจะถูกประเมินในการเรียก "รับ" ดังนั้นจึงมีการประเมินการเข้าถึงแต่ละครั้ง ทางเลือกแบบคลาสสิก (โดยใช้ตัวจัดการ KeyError หรือเพรดิเคต) คือการประเมินค่าเริ่มต้นเฉพาะในกรณีที่ไม่มีคีย์ สิ่งนี้อนุญาตให้สร้างการปิด / แลมบ์ดาหนึ่งครั้งและประเมินผลบนคีย์ที่หายไป
Tom Stambaugh

142

อะไรคือสิ่งที่dict.get()วิธี?

ดังกล่าวแล้วgetวิธีการมีพารามิเตอร์เพิ่มเติมซึ่งบ่งชี้ถึงค่าที่ขาดหายไป จากเอกสารประกอบ

get(key[, default])

ส่งคืนค่าสำหรับคีย์หากคีย์อยู่ในพจนานุกรมมิฉะนั้นจะเป็นค่าเริ่มต้น KeyErrorหากเริ่มต้นจะไม่ได้รับค่าเริ่มต้นจะไม่มีดังนั้นว่าวิธีนี้ไม่เคยยก

ตัวอย่างสามารถ

>>> 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

มีการปรับปรุงความเร็วทุกที่หรือไม่?

ตามที่กล่าวไว้ที่นี่ ,

ดูเหมือนว่าทั้งสามวิธีตอนนี้แสดงประสิทธิภาพที่คล้ายกัน (ภายในประมาณ 10% ของกันและกัน) มากหรือน้อยขึ้นอยู่กับคุณสมบัติของรายการคำ

ก่อน getช้าลงอย่างมากอย่างไรก็ตามขณะนี้ความเร็วใกล้เคียงกับพร้อมกับข้อดีเพิ่มเติมของการคืนค่าเริ่มต้น แต่เพื่อล้างแบบสอบถามทั้งหมดของเราเราสามารถทดสอบในรายการที่ค่อนข้างใหญ่ (โปรดทราบว่าการทดสอบรวมถึงการค้นหาคีย์ที่ถูกต้องทั้งหมดเท่านั้น)

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

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

ตอนนี้เวลาทั้งสองฟังก์ชั่นการใช้งาน 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

อย่างที่เราเห็นการค้นหานั้นเร็วกว่าการค้นหาเนื่องจากไม่มีฟังก์ชั่นการค้นหา สามารถมองเห็นผ่านdis

>>> 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  

มันจะมีประโยชน์ที่ไหน?

มันจะมีประโยชน์เมื่อใดก็ตามที่คุณต้องการให้ค่าเริ่มต้นเมื่อใดก็ตามที่คุณค้นหาพจนานุกรม สิ่งนี้จะช่วยลด

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

บรรทัดเดียว val = dic.get(key,def_val)

มันจะไม่มีประโยชน์ที่ไหน?

เมื่อใดก็ตามที่คุณต้องการกลับKeyErrorระบุว่าคีย์เฉพาะไม่สามารถใช้ได้ การส่งคืนค่าเริ่มต้นยังมีความเสี่ยงที่ค่าเริ่มต้นที่เฉพาะเจาะจงอาจเป็นกุญแจเช่นกัน!

เป็นไปได้ไหมที่จะมีgetฟีเจอร์ที่ชอบdict['key']?

ใช่ เราจำเป็นต้องดำเนินการ__missing__ในคลาสย่อย dict

โปรแกรมตัวอย่างสามารถ

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

การสาธิตเล็ก ๆ สามารถ

>>> my_d = MyDict({1:2,2:3})
>>> my_d[1]
2
>>> my_d[3]
>>> repr(my_d[3])
'None'

32
คำตอบ StackOverflow มาตรฐานทองคำ!
Apollo Data


1
หนึ่งในการทดสอบที่ดีมากขึ้นจะเทียบif k in dict and dict[k]: if dict.get(k):ครอบคลุมสถานการณ์นี้เมื่อเราต้องตรวจสอบว่าที่สำคัญมีอยู่และถ้า 'ใช่' - สิ่งที่มีค่า ?, dict = {1: '', 2: 'some value'}สิ่งที่ชอบ:
TitanFighter

7
โปรดจำไว้ว่าค่าเริ่มต้นจะได้รับการประเมินโดยไม่คำนึงถึงค่าที่อยู่ในพจนานุกรมดังนั้นแทนที่จะ dictionary.get(value, long_function())เป็นหนึ่งในการพิจารณาใช้dictionary.get(value) or long_function()
Kresimir

Ah @Kresimir จริง ฉันได้รับคำถามนั้นในการสัมภาษณ์ครั้งหนึ่งที่ฉันเผชิญ (ฉันไม่รู้เกี่ยวกับมันเมื่อฉันโพสต์คำตอบนี้ไว้) ขอบคุณสำหรับการเตือนฉันเกี่ยวกับเรื่องนี้.
Bhargav Rao

32

getใช้ค่าที่สองเป็นทางเลือก หากคีย์ที่ระบุไม่มีอยู่ในพจนานุกรมของคุณค่านี้จะถูกส่งกลับ

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

หากคุณไม่ระบุพารามิเตอร์ที่สองNoneจะถูกส่งคืน

ถ้าคุณใช้การจัดทำดัชนีในขณะที่คีย์ไม่มีอยู่จะเพิ่มdictionary['Year']KeyError


19

ฉันจะให้ตัวอย่างที่เป็นประโยชน์ในการคัดลอกข้อมูลเว็บโดยใช้ไพ ธ อนหลายครั้งที่คุณจะได้รับคีย์โดยไม่มีค่าในกรณีเหล่านี้คุณจะได้รับข้อผิดพลาดหากคุณใช้พจนานุกรม ['คีย์'] ในขณะที่ dictionary.get ('คีย์) ',' return_otherwise ') ไม่มีปัญหา

ในทำนองเดียวกันฉันจะใช้ '' .join (รายการ) ตรงข้ามกับรายการ [0] ถ้าคุณพยายามที่จะจับค่าเดียวจากรายการ

หวังว่ามันจะช่วย

[แก้ไข] นี่คือตัวอย่างที่ใช้งานได้จริง:

สมมติว่าคุณกำลังเรียก API ซึ่งส่งคืนไฟล์ JOSN ที่คุณต้องแยกวิเคราะห์ JSON แรกมีลักษณะดังนี้:

{"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 ที่สองเป็นเช่นนี้:

{"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"}}

โปรดทราบว่า JSON ตัวที่สองไม่มีคีย์ "submitdate_ts" ซึ่งค่อนข้างปกติในโครงสร้างข้อมูลใด ๆ

ดังนั้นเมื่อคุณพยายามที่จะเข้าถึงค่าของคีย์นั้นในลูปคุณสามารถเรียกมันโดยใช้ค่าต่อไปนี้:

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

คุณทำได้ แต่จะให้ข้อผิดพลาดในการย้อนกลับสำหรับบรรทัด JSON บรรทัดที่สองเนื่องจากคีย์นั้นไม่มีอยู่จริง

วิธีการเข้ารหัสที่เหมาะสมอาจเป็นดังต่อไปนี้:

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

{'x': ไม่มี} เพื่อหลีกเลี่ยงข้อผิดพลาดระดับที่สอง แน่นอนคุณสามารถสร้างความทนทานต่อความผิดพลาดได้มากขึ้นในรหัสถ้าคุณทำการขูด เช่นแรกระบุเงื่อนไขถ้า


2
คำตอบที่ดีโพสต์ต่อหน้าคนอื่น ๆ ซึ่งน่าจะได้รับการสนับสนุนมากขึ้นและอาจเป็นที่ยอมรับถ้าคุณโพสต์ตัวอย่างโค้ด (+1 จากฉัน)
Mawg กล่าวว่าการคืนสถานะโมนิก้า

2
@Mawg ฉันเพิ่งมีโครงการขูดเพื่อการวิจัยของฉัน มันกำลังเรียก API และแยกไฟล์ JSON โดยทั่วไป ฉันให้ RA ของฉันทำ หนึ่งในปัญหาสำคัญที่เขาได้รับคือการเรียกใช้กุญแจโดยตรงเมื่อมีกุญแจจำนวนมากหายไป ฉันจะโพสต์ตัวอย่างในข้อความด้านบน
วิน

ขอบคุณสำหรับการแก้ปัญหาในแง่มุมหลายมิติของสิ่งนี้! ดูเหมือนคุณจะสามารถทำได้ {} แทนที่จะ {'x': None}
bluppfisk

17

จุดประสงค์คือคุณสามารถให้ค่าเริ่มต้นหากไม่พบกุญแจซึ่งมีประโยชน์มาก

dictionary.get("Name",'harry')

8

ฟังก์ชั่นนี้มีประโยชน์สำหรับวัตถุประสงค์ใด?

การใช้งานอย่างหนึ่งอย่างคือการนับด้วยพจนานุกรม สมมติว่าคุณต้องการนับจำนวนการปรากฏของแต่ละองค์ประกอบในรายการที่กำหนด วิธีทั่วไปในการทำเช่นนั้นก็คือการสร้างพจนานุกรมโดยที่กุญแจคือองค์ประกอบและค่าคือจำนวนครั้งที่เกิดขึ้น

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

เมื่อใช้.get()วิธีนี้คุณสามารถทำให้โค้ดนี้กะทัดรัดและชัดเจนยิ่งขึ้น:

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

7

gotcha ที่ต้องระวังเมื่อใช้ .get() :

ถ้าพจนานุกรมมีคีย์ที่ใช้ในการเรียกร้องให้.get()และค่าที่เป็นNoneที่.get()วิธีการที่จะกลับมาNoneแม้ว่าค่าเริ่มต้นเป็นที่จัดทำ

ตัวอย่างเช่นผลตอบแทนต่อไปนี้Noneไม่ใช่'alt_value'อย่างที่คาดไว้:

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

.get()Noneเป็นค่าที่สองจะถูกส่งกลับเฉพาะในกรณีที่สำคัญที่ให้มาไม่ได้อยู่ในพจนานุกรมไม่ได้ถ้าค่าตอบแทนของการเรียกร้องที่เป็น


1
อันนี้มีฉัน: วิธีหนึ่งที่จะแก้ปัญหานี้ก็คือd.get('key') or 'alt_value'ถ้าคุณรู้ว่ามันอาจเป็นได้None
Daniel Holmes

4

ทำไม dict.get (กุญแจ) แทนที่จะเป็น dict [key]

0. สรุป

เมื่อเปรียบเทียบกับdict[key],dict.getมีค่าทางเลือกเมื่อมองขึ้นสำหรับคีย์

1. คำจำกัดความ

รับ (คีย์ [ค่าเริ่มต้น]) 4. ประเภทในตัว - เอกสาร Python 3.6.4rc1

ส่งคืนค่าสำหรับคีย์หากคีย์อยู่ในพจนานุกรมมิฉะนั้นจะเป็นค่าเริ่มต้น หากไม่ได้กำหนดค่าเริ่มต้นจะมีค่าเริ่มต้นเป็นไม่มีดังนั้นวิธีนี้จะไม่เพิ่ม 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. ปัญหามันแก้ไข

หากไม่มีdefault valueคุณต้องเขียนรหัสที่ยุ่งยากเพื่อจัดการกับข้อยกเว้นดังกล่าว

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'

ในฐานะที่เป็นวิธีแก้ไขปัญหาที่สะดวกdict.getแนะนำค่าเริ่มต้นที่เป็นทางเลือกให้หลีกเลี่ยงโค้ดข้างบน

3. สรุป

dict.get มีตัวเลือกค่าเริ่มต้นเพิ่มเติมเพื่อจัดการกับข้อยกเว้นหากไม่มีรหัสจากพจนานุกรม


0

ข้อแตกต่างอย่างหนึ่งที่อาจเป็นประโยชน์คือถ้าเรากำลังมองหากุญแจที่ไม่มีอยู่เราจะได้รับ None ไม่เหมือนเมื่อเราใช้เครื่องหมายวงเล็บในกรณีนี้เราจะได้รับข้อผิดพลาด:

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

สิ่งสุดท้ายที่เจ๋งเกี่ยวกับวิธีการรับคือว่ามันจะได้รับอาร์กิวเมนต์ตัวเลือกเพิ่มเติมสำหรับค่าเริ่มต้นนั่นคือถ้าเราพยายามที่จะรับค่าคะแนนของนักเรียน แต่นักเรียนไม่มีรหัสคะแนนที่เราจะได้รับ 0 แทน

ดังนั้นแทนที่จะทำสิ่งนี้ (หรือสิ่งที่คล้ายกัน):

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

พวกเราสามารถทำได้:

score = dictionary.get("score", 0)
# score = 0

-1

ขึ้นอยู่กับการใช้งานควรใช้getวิธีนี้

example1

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

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

Out[15]: False

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

Out[16]: ''

example2

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'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.