Tại sao dict.get (khóa) thay vì dict [key]?


651

Hôm nay, tôi đã xem qua dictphương thức get, được cung cấp một khóa trong từ điển, trả về giá trị liên quan.

Vì mục đích gì chức năng này hữu ích? Nếu tôi muốn tìm một giá trị được liên kết với khóa trong từ điển, tôi chỉ có thể làm dict[key]và nó trả về cùng một điều:

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

1
dictionary["foo"]dictionary.get("foo")hành xử khác nhau, mặc dù.
Niklas B.

34
dictionary.get("Age") cũng giống như viết dictionary["Age"] or None nên nó xử lý ngầm ngoại lệ KeyError
yosemite_k

5
@yosemite_k Tôi có thể thiếu một số bối cảnh ở đây, nhưng dictionary['non-existent key'] or Nonenên và vẫn nâng cao KeyErrorcho tôi (tối đa v3.6). Bạn có thể giải thích những gì bạn có ý nghĩa?
nivk

@nivk dictionary ['khóa không tồn tại'] gây ra lỗi và lỗi đó cần được xử lý rõ ràng. nếu thay vào đó, bạn sử dụng dictionary.get () (có nghĩa đen là từ điển ['khóa không tồn tại'] hoặc Không có) ngoại lệ đó được xử lý ngầm.
yosemite_k

Câu trả lời:


992

Nó cho phép bạn cung cấp một giá trị mặc định nếu khóa bị thiếu:

dictionary.get("bogus", default_value)

trả về default_value(bất cứ điều gì bạn chọn nó là), trong khi

dictionary["bogus"]

sẽ tăng a KeyError.

Nếu bỏ qua, default_valueNone, như vậy

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

trả lại Nonegiống như

dictionary.get("bogus", None)

sẽ.


1
Điều này sẽ giống như dictionary.get("bogus") or my_default? Tôi đã thấy mọi người sử dụng nó trong một số trường hợp và tôi đã tự hỏi liệu có bất kỳ lợi thế nào của việc sử dụng cái này thay vì cái khác (ngoài khả năng đọc)
Thuật toán

15
@MustafaS: Nếu "bogus"là một khóa trong dictionarydictionary.get("bogus")trả về một giá trị ước tính thành Sai trong ngữ cảnh boolean (tức là giá trị Falsey), chẳng hạn như 0 hoặc chuỗi rỗng '', thì dictionary.get("bogus") or my_defaultsẽ đánh giá my_defaulttrong khi đó dictionary.get("bogus", my_default)sẽ trả về giá trị Falsey. Vì vậy, không, dictionary.get("bogus") or my_defaultkhông tương đương với dictionary.get("bogus", my_default). Việc sử dụng phụ thuộc vào hành vi bạn mong muốn.
unutbu

3
@MustafaS: Ví dụ: giả sử x = {'a':0}. Sau đó x.get('a', 'foo')trả lại 0nhưng x.get('a') or 'foo'trả lại 'foo'.
unutbu

3
Một cảnh báo có thể xảy ra khi sử dụng dictionary.get('key'): Có thể gây nhầm lẫn nếu các giá trị trong từ điển là None. Nếu không chỉ định giá trị trả về (đối số tùy chọn thứ hai), không có cách nào để xác minh xem khóa không tồn tại hay nếu giá trị của nó là None. Trong trường hợp cụ thể này, tôi sẽ xem xét sử dụng try-except-KeyError.
Aart Goossens

1
Cần lưu ý rằng biểu thức chỉ định giá trị mặc định được ước tính trong lệnh gọi "get" và do đó được đánh giá trên mỗi lần truy cập. Một cách thay thế cổ điển (sử dụng trình xử lý KeyError hoặc biến vị ngữ) là để đánh giá giá trị mặc định chỉ khi khóa bị thiếu. Điều này cho phép đóng / lambda được tạo một lần và đánh giá trên bất kỳ khóa bị thiếu nào.
Tom Stambaugh

142

Là gì dict.get()phương pháp?

Như đã đề cập, getphương thức chứa một tham số bổ sung cho biết giá trị còn thiếu. Từ tài liệu

get(key[, default])

Trả về giá trị cho khóa nếu khóa nằm trong từ điển, mặc định khác. Nếu mặc định không được đưa ra, nó mặc định là Không có, do đó phương thức này không bao giờ tăng a KeyError.

Một ví dụ có thể là

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

Có cải thiện tốc độ ở bất cứ đâu?

Như đã đề cập ở đây ,

Dường như cả ba cách tiếp cận hiện đều thể hiện hiệu suất tương tự (trong khoảng 10% so với nhau), ít nhiều độc lập với các thuộc tính của danh sách các từ.

Trước đó getchậm hơn đáng kể, tuy nhiên bây giờ tốc độ gần như tương đương cùng với lợi thế bổ sung là trả về giá trị mặc định. Nhưng để xóa tất cả các truy vấn của chúng tôi, chúng tôi có thể kiểm tra trên một danh sách khá lớn (Lưu ý rằng kiểm tra chỉ bao gồm tìm kiếm tất cả các khóa hợp lệ)

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

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

Bây giờ tính thời gian hai chức năng này bằng cách sử dụng 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

Như chúng ta có thể thấy việc tra cứu nhanh hơn get vì không có chức năng tra cứu. Điều này có thể được nhìn thấy thông quadis

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

Nó sẽ hữu ích ở đâu?

Nó sẽ hữu ích bất cứ khi nào bạn muốn cung cấp một giá trị mặc định bất cứ khi nào bạn đang tra từ điển. Điều này làm giảm

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

Đến một dòng val = dic.get(key,def_val)

Nó sẽ KHÔNG hữu ích ở đâu?

Bất cứ khi nào bạn muốn trả lại một thông KeyErrorbáo rằng khóa cụ thể không có sẵn. Trả lại một giá trị mặc định cũng có rủi ro rằng một giá trị mặc định cụ thể cũng có thể là một khóa!

Có thể có gettính năng như trong dict['key']?

Đúng! Chúng ta cần thực hiện __missing__trong một lớp con dict.

Một chương trình mẫu có thể là

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

Một cuộc biểu tình nhỏ có thể là

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

32
Tiêu chuẩn vàng của câu trả lời StackOverflow!
Dữ liệu Apollo


1
Một thử nghiệm tốt hơn sẽ là if k in dict and dict[k]:vs if dict.get(k):. Điều này bao gồm tình huống khi chúng ta cần kiểm tra xem khóa có tồn tại không và nếu 'có' - giá trị nào?, Đại loại như : dict = {1: '', 2: 'some value'}.
TitanFighter

7
Xin nhớ rằng giá trị mặc định được đánh giá bất kể giá trị có trong từ điển, vì vậy thay vì dictionary.get(value, long_function())người ta có thể cân nhắc sử dụngdictionary.get(value) or long_function()
Kresimir

À @Kresimir, đúng rồi. Tôi đã nhận được câu hỏi đó trong một trong những cuộc phỏng vấn mà tôi phải đối mặt (tôi không biết về nó khi tôi đã đăng câu trả lời này ban đầu). Cảm ơn đã nhắc nhở tôi về nó.
Bhargav Rao

32

getmất một giá trị tùy chọn thứ hai. Nếu khóa được chỉ định không tồn tại trong từ điển của bạn, thì giá trị này sẽ được trả về.

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

Nếu bạn không đưa ra tham số thứ hai, Nonesẽ được trả về.

Nếu bạn sử dụng lập chỉ mục như trong dictionary['Year'], các khóa không tồn tại sẽ tăng KeyError.


19

Tôi sẽ đưa ra một ví dụ thực tế trong việc loại bỏ dữ liệu web bằng python, rất nhiều lần bạn sẽ nhận được các khóa không có giá trị, trong những trường hợp đó bạn sẽ gặp lỗi nếu bạn sử dụng từ điển ['key'], trong khi dictionary.get ('key ',' return_therwise ') không có vấn đề gì.

Tương tự, tôi sẽ sử dụng '' .join (danh sách) trái ngược với danh sách [0] nếu bạn cố gắng nắm bắt một giá trị từ danh sách.

hy vọng nó giúp.

[Chỉnh sửa] Đây là một ví dụ thực tế:

Giả sử, bạn đang gọi API, trả về tệp JOSN mà bạn cần phân tích cú pháp. JSON đầu tiên trông như sau:

{"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 thứ hai là như thế này:

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

Lưu ý rằng JSON thứ hai thiếu khóa "submitdate_ts", điều này khá bình thường trong bất kỳ cấu trúc dữ liệu nào.

Vì vậy, khi bạn cố gắng truy cập giá trị của khóa đó trong một vòng lặp, bạn có thể gọi nó bằng cách sau:

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

Bạn có thể, nhưng nó sẽ cung cấp cho bạn một lỗi truy nguyên cho dòng JSON thứ hai, vì khóa đơn giản là không tồn tại.

Cách mã hóa thích hợp này, có thể là như sau:

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

{'x': Không} ở đó để tránh mức thứ hai gặp lỗi. Tất nhiên bạn có thể xây dựng khả năng chịu lỗi nhiều hơn vào mã nếu bạn đang thực hiện quét. Giống như lần đầu tiên chỉ định một điều kiện if


2
Một câu trả lời hay, được đăng trước bất kỳ câu hỏi nào khác, sẽ được nâng cấp nhiều hơn và có thể được chấp nhận, nếu bạn đã đăng một số ví dụ về mã (mặc dù +1 từ tôi)
Mawg nói rằng phục hồi Monica

2
@Mawg Gần đây tôi đã có một dự án cạo cho nghiên cứu của tôi. Về cơ bản, nó đã gọi một API và phân tích cú pháp các tệp JSON. Tôi đã có RA của tôi làm điều đó. Một trong những vấn đề quan trọng mà anh gặp phải là gọi trực tiếp khóa, khi nhiều khóa thực sự bị thiếu. Tôi sẽ đăng một ví dụ trong văn bản trên.
kevin

cảm ơn vì đã giải quyết khía cạnh đa chiều của việc này! Âm thanh như bạn thậm chí chỉ có thể làm {} thay vì {'x': Không}
bluppfisk

17

Mục đích là bạn có thể đưa ra một giá trị mặc định nếu không tìm thấy khóa, điều này rất hữu ích

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

8

Vì mục đích gì chức năng này hữu ích?

Một cách sử dụng cụ thể là đếm với một từ điển. Giả sử bạn muốn đếm số lần xuất hiện của từng yếu tố trong một danh sách nhất định. Cách phổ biến để làm như vậy là tạo một từ điển trong đó các khóa là các phần tử và giá trị là số lần xuất hiện.

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

Sử dụng .get()phương thức, bạn có thể làm cho mã này gọn hơn và rõ ràng hơn:

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

7

Một chú ý để ý khi sử dụng .get() :

Nếu từ điển chứa khóa được sử dụng trong lệnh gọi .get()và giá trị của nó là None, .get()phương thức sẽ trả vềNone ngay cả khi giá trị mặc định được cung cấp.

Ví dụ, lợi nhuận sau đây None, không 'alt_value'như mong đợi:

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

.get()Giá trị thứ hai chỉ được trả về nếu khóa được cung cấp KHÔNG có trong từ điển, không phải nếu giá trị trả về của cuộc gọi đó là None.


1
Điều này giúp tôi: \ Một cách để giải quyết vấn đề này là có d.get('key') or 'alt_value'nếu bạn biết nó có thểNone
Daniel Holmes

4

Tại sao dict.get (khóa) thay vì dict [key]?

0. Tóm tắt

So sánh với dict[key], dict.getcung cấp một giá trị dự phòng khi tìm kiếm một khóa.

1. Định nghĩa

get (key [, default]) 4. Các loại tích hợp - Tài liệu Python 3.6.4rc1

Trả về giá trị cho khóa nếu khóa nằm trong từ điển, mặc định khác. Nếu mặc định không được cung cấp, nó mặc định là Không có, do đó phương thức này không bao giờ tăng 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. Vấn đề nó giải quyết.

Nếu không default value, bạn phải viết mã rườm rà để xử lý một ngoại lệ như vậy.

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'

Là một giải pháp tiện lợi, dict.getgiới thiệu một giá trị mặc định tùy chọn tránh các mã không mong muốn ở trên.

3. Kết luận

dict.get có một tùy chọn giá trị mặc định bổ sung để xử lý ngoại lệ nếu khóa không có trong từ điển


0

Một điểm khác biệt, có thể là một lợi thế, là nếu chúng ta đang tìm kiếm một khóa không tồn tại, chúng ta sẽ không nhận được, không giống như khi chúng ta sử dụng ký hiệu ngoặc, trong trường hợp đó chúng ta sẽ bị ném lỗi:

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

Điều cuối cùng thú vị về phương thức get, là nó nhận được một đối số tùy chọn bổ sung cho một giá trị mặc định, đó là nếu chúng ta cố gắng lấy giá trị điểm của một học sinh, nhưng học sinh không có khóa điểm chúng ta có thể nhận được thay vào đó là 0

Vì vậy, thay vì làm điều này (hoặc một cái gì đó tương tự):

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

Chung ta co thể lam được việc nay:

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

-1

Dựa vào cách sử dụng nên sử dụng getphương pháp này .

Ví dụ 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]: ''

Ví dụ2

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'
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.