Dlaczego dict.get (klucz) zamiast dict [klucz]?


649

Dzisiaj natknąłem się na dictmetodę, getktóra po podaniu klucza w słowniku zwraca powiązaną wartość.

W jakim celu przydatna jest ta funkcja? Jeśli chciałbym znaleźć wartość powiązaną z kluczem w słowniku, mogę to zrobić dict[key]i zwraca to samo:

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

1
dictionary["foo"]i dictionary.get("foo")zachowują się jednak inaczej.
Niklas B.,

34
dictionary.get("Age") jest taki sam jak pisanie, dictionary["Age"] or None więc domyślnie obsługuje wyjątek KeyError
yosemite_k

5
@yosemite_k Być może brakuje mi tu jakiegoś kontekstu, ale dictionary['non-existent key'] or Nonepowinienem i nadal podnosi KeyErrordla mnie (do wersji 3.6). Czy możesz wyjaśnić, co masz na myśli?
nivk

Słownik @nivk [„nieistniejący klucz”] wywołuje błąd, który powinien zostać wyraźnie obsłużony. jeśli zamiast tego użyjesz dictionary.get () (który dosłownie funkcjonuje jako słownik [„nieistniejący klucz”] lub Brak), wyjątek ten jest domyślnie obsługiwany.
yosemite_k

Odpowiedzi:


991

Pozwala podać wartość domyślną, jeśli brakuje klucza:

dictionary.get("bogus", default_value)

zwraca default_value(cokolwiek wybierzesz), podczas gdy

dictionary["bogus"]

podniósłby KeyError.

Jeśli pominięto, default_value oznacza to None, że

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

zwraca Nonetak jak

dictionary.get("bogus", None)

by.


1
Czy to byłoby to samo co dictionary.get("bogus") or my_default? Widziałem ludzi, którzy używają go w niektórych przypadkach i zastanawiałem się, czy jest jakaś korzyść z używania jednego zamiast drugiego (innego niż czytelność)
Algorytmiczny

15
@MustafaS: Jeśli "bogus"jest kluczem dictionaryi dictionary.get("bogus")zwraca wartość, która zwraca wartość False w kontekście boolowskim (tj. Wartość Falsey), taką jak 0 lub pusty ciąg '', wówczas dictionary.get("bogus") or my_defaultocenia na, my_defaultpodczas gdy dictionary.get("bogus", my_default)zwraca wartość Falsey. Więc nie, dictionary.get("bogus") or my_defaultnie jest równoważne z dictionary.get("bogus", my_default). Które stosować zależy od pożądanego zachowania.
unutbu

3
@MustafaS: Załóżmy na przykład x = {'a':0}. Potem x.get('a', 'foo')wraca, 0ale x.get('a') or 'foo'wraca 'foo'.
unutbu

3
Jedno możliwe zastrzeżenie przy użyciu dictionary.get('key'): Może być mylące, jeśli wartości w słowniku są None. Bez podania wartości zwracanej (drugi opcjonalny argument) nie ma sposobu, aby sprawdzić, czy klucz nie istnieje lub czy jego wartość to None. W tym konkretnym przypadku rozważyłbym użycie try-except-KeyError.
Aart Goossens,

1
Warto zauważyć, że wyrażenie określające wartość domyślną jest oceniane w wywołaniu „get”, a zatem jest oceniane przy każdym dostępie. Klasyczną alternatywą (za pomocą modułu obsługi KeyError lub predykatu) jest ocena wartości domyślnej tylko w przypadku braku klucza. Umożliwia to jednokrotne utworzenie zamknięcia / lambda i ocenę dowolnego brakującego klucza.
Tom Stambaugh,

142

Jaka jest dict.get()metoda

Jak już wspomniano, getmetoda zawiera dodatkowy parametr wskazujący brakującą wartość. Z dokumentacji

get(key[, default])

Zwróć wartość klucza, jeśli klucz znajduje się w słowniku, w przeciwnym razie wartość domyślna. Jeśli wartość domyślna nie jest podana, wartość domyślna to Brak, dzięki czemu ta metoda nigdy nie wywołuje wartości a KeyError.

Przykładem może być

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

Czy są jakieś ulepszenia prędkości?

Jak wspomniano tutaj ,

Wydaje się, że wszystkie trzy podejścia wykazują teraz podobną wydajność (w odległości około 10% od siebie), mniej więcej niezależną od właściwości listy słów.

Wcześniej getbyło znacznie wolniejsze, ale teraz prędkość jest prawie porównywalna wraz z dodatkową zaletą zwracania wartości domyślnej. Ale aby wyczyścić wszystkie nasze zapytania, możemy przetestować na dość dużej liście (pamiętaj, że test obejmuje sprawdzenie tylko wszystkich prawidłowych kluczy)

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

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

Teraz odmierzamy czas przy użyciu tych dwóch funkcji 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

Jak widzimy, wyszukiwanie jest szybsze niż pobieranie, ponieważ nie ma wyszukiwania funkcji. Można to zobaczyć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  

Gdzie to się przyda?

Przyda się, gdy chcesz podać wartość domyślną, gdy szukasz słownika. To redukuje

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

Do jednej linii val = dic.get(key,def_val)

Gdzie to NIE będzie przydatne?

Ilekroć chcesz zwrócić informację KeyError, że dany klucz nie jest dostępny. Zwrócenie wartości domyślnej niesie również ryzyko, że określona wartość domyślna może być kluczem!

Czy można mieć getpodobną funkcję dict['key']?

Tak! Musimy wdrożyć__missing__ podklasę dict.

Przykładowy program może być

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

Może być mała demonstracja

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

32
Złoty standard odpowiedzi StackOverflow!
Dane Apollo z


1
Jeszcze jeden dobry test byłby if k in dict and dict[k]:vs if dict.get(k):. Dotyczy to sytuacji, gdy musimy sprawdzić, czy klucz istnieje, a jeśli „tak” - jaką wartość ?, coś takiego: dict = {1: '', 2: 'some value'}.
TitanFighter

7
Pamiętaj, że wartość domyślna jest obliczana niezależnie od wartości znajdującej się w słowniku, więc zamiast dictionary.get(value, long_function())rozważać użyciedictionary.get(value) or long_function()
Kresimir

Ach @Kresimir, prawda. Dostałem to pytanie w jednym z wywiadów, z którymi się spotkałem (nie wiedziałem o tym, kiedy pierwotnie opublikowałem tę odpowiedź). Dzięki za przypomnienie mi o tym.
Bhargav Rao

32

getprzyjmuje drugą opcjonalną wartość. Jeśli określony klucz nie istnieje w słowniku, ta wartość zostanie zwrócona.

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

Jeśli nie podasz drugiego parametru, Nonezostanie zwrócony.

Jeśli użyjesz indeksowania jak w dictionary['Year'], nieistniejące klucze wzrosną KeyError.


19

Podam praktyczny przykład skrobania danych internetowych przy użyciu Pythona, często dostajesz klucze bez wartości, w takich przypadkach będziesz otrzymywać błędy, jeśli użyjesz słownika ['klucz'], podczas gdy dictionary.get ('klucz „,” return_otherwise ”) nie ma problemów.

Podobnie użyłbym '' .join (lista) w przeciwieństwie do listy [0], jeśli spróbujesz przechwycić pojedynczą wartość z listy.

mam nadzieję, że to pomoże.

[Edytuj] Oto praktyczny przykład:

Załóżmy, że wywołujesz interfejs API, który zwraca plik JOSN, który musisz przeanalizować. Pierwszy JSON wygląda następująco:

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

Drugi JOSN wygląda tak:

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

Zauważ, że w drugim JSON brakuje klucza „submdate_ts”, co jest dość normalne w każdej strukturze danych.

Więc kiedy próbujesz uzyskać dostęp do wartości tego klucza w pętli, możesz wywołać go w następujący sposób:

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

Możesz, ale spowoduje to błąd śledzenia dla drugiej linii JSON, ponieważ klucz po prostu nie istnieje.

Odpowiednim sposobem zakodowania tego może być:

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

{'x': Brak} ma na celu uniknięcie błędu drugiego poziomu. Oczywiście, jeśli robisz skrobanie, możesz wbudować w kod większą tolerancję na błędy. Jak pierwsze określenie warunku if


2
Dobra odpowiedź, opublikowana przed którąkolwiek z pozostałych, która byłaby bardziej oceniona i prawdopodobnie zaakceptowana, gdybyś opublikował kilka przykładów kodu (chociaż +1 ode mnie)
Mawg mówi, że przywraca Monikę

2
@Mawg Niedawno miałem projekt zgarniania do moich badań. Wywołał API i parsował pliki JSON w zasadzie. Kazałem mojej RA zrobić to. Jedną z kluczowych kwestii, które miał, było bezpośrednie wywołanie klucza, gdy faktycznie brakuje wielu kluczy. Podam przykład w powyższym tekście.
kevin

dzięki za zajęcie się wielowymiarowym aspektem tego! Wygląda na to, że możesz nawet zrobić {} zamiast {'x': None}
bluppfisk

17

Celem jest podanie wartości domyślnej, jeśli klucz nie zostanie znaleziony, co jest bardzo przydatne

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

8

W jakim celu przydatna jest ta funkcja?

Jednym szczególnym zastosowaniem jest liczenie ze słownikiem. Załóżmy, że chcesz policzyć liczbę wystąpień każdego elementu na danej liście. Częstym sposobem jest utworzenie słownika, w którym klucze są elementami, a wartości są liczbą wystąpień.

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

Za pomocą tej .get()metody możesz uczynić ten kod bardziej zwartym i przejrzystym:

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

7

Musisz wiedzieć, kiedy używasz .get():

Jeśli słownik zawiera klucz użyty w wywołaniu, .get()a jego wartość to None, .get()metoda zwróci, Nonenawet jeśli zostanie podana wartość domyślna.

Na przykład następujące zwroty Nonenie 'alt_value'są zgodne z oczekiwaniami:

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

.get()Druga wartość jest zwracana tylko wtedy, gdy dostarczony klucz NIE znajduje się w słowniku, a nie, jeśli zwracana jest wartość tego wywołania None.


1
Ten dostał mnie: \ Jednym ze sposobów rozwiązania tego jest posiadanie, d.get('key') or 'alt_value'jeśli wiesz, że to może byćNone
Daniel Holmes

4

Dlaczego dict.get (klucz) zamiast dict [klucz]?

0. Podsumowanie

W porównaniu do dict[key], dict.getzapewnia rezerwową wartość przy wyszukiwaniu klucza.

1. Definicja

get (klucz [, domyślnie]) 4. Typy wbudowane - dokumentacja Python 3.6.4rc1

Zwróć wartość klucza, jeśli klucz znajduje się w słowniku, w przeciwnym razie wartość domyślna. Jeśli wartość domyślna nie zostanie podana, domyślnie zostanie ustawiona wartość Brak, dzięki czemu ta metoda nigdy nie wywołuje błędu klucza.

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. Problem rozwiązuje.

Jeśli nie default value, musisz napisać kłopotliwe kody, aby obsłużyć taki wyjątek.

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'

Jako wygodne rozwiązanie dict.getwprowadza opcjonalną wartość domyślną, unikając nieporadnych kodów.

3. Wniosek

dict.get ma dodatkową opcję wartości domyślnej, aby poradzić sobie z wyjątkiem, jeśli nie ma klucza w słowniku


0

Jedną różnicą, która może być zaletą, jest to, że jeśli szukamy klucza, który nie istnieje, otrzymamy Brak, nie tak jak w przypadku notacji w nawiasach, w którym to przypadku zostanie zgłoszony błąd:

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

Ostatnią rzeczą, która jest fajna w metodzie get, jest to, że otrzymuje ona dodatkowy opcjonalny argument za wartością domyślną, to znaczy, jeśli próbujemy uzyskać wartość punktową ucznia, ale uczeń nie ma klucza oceny, który możemy uzyskać zamiast tego 0.

Zamiast robić to (lub coś podobnego):

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

Możemy to zrobić:

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

-1

W zależności od użycia należy użyć tej getmetody.

Przykład 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]: ''

Przykład 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'
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.