Zwróć Brak, jeśli klucz Słownika nie jest dostępny

489

Potrzebuję sposobu, aby uzyskać wartość słownika, jeśli jego klucz istnieje, lub po prostu wrócić None, jeśli nie istnieje.

Jednak Python zgłasza KeyErrorwyjątek, jeśli szukasz klucza, który nie istnieje. Wiem, że mogę sprawdzić klucz, ale szukam czegoś bardziej wyraźnego. Czy istnieje sposób, aby po prostu wrócić, Nonejeśli klucz nie istnieje?

Spyros
źródło
74
Po prostu użyj .get(key)zamiast[key]
Gabe
12
Dict podnosi wyjątek KeyError. Nie „zwraca key_error”.
Ber
3
Dostęp do klucza i wyłapanie wyjątku jest w Pythonie w porządku. Jest to nawet dobrze znany i często używany wzór. Jeśli zamiast tego zwrócisz None, nie będzie możliwe zapisanie None jako wartości, co może mieć znaczenie w niektórych przypadkach.
Ber
1
Czasami chcesz traktować „brak” wpisów w słowniku i brakujących wpisów w ten sam sposób, w takim przypadku zaakceptowana odpowiedź wydaje się dobrze wykonywać zadanie.
cib
@ Ber Zredagowałem pytanie, aby wyjaśnić. Ty też mogłeś to zrobić.
törzsmókus

Odpowiedzi:

813

Możesz użyć dict.get()

value = d.get(key)

który zwróci Nonejeśli key is not in d. Możesz także podać inną wartość domyślną, która zostanie zwrócona zamiast None:

value = d.get(key, "empty")
Tim Pietzcker
źródło
47
Zauważ, że drugi wariant z domyślną rezerwą nadal będzie zwracany, Nonejeśli klucz zostanie wyraźnie zamapowany Nonew nagraniu. Jeśli nie tego chcesz, możesz użyć czegoś takiego d.get(key) or "empty".
cib
15
@cib: Racja, ale rozwiązanie ma podobny problem - jeśli klucz jest odwzorowany do dowolnego „falsy” wartości (jak [], "", False, 0.0lub rzeczywiście None), to rozwiązanie będzie zawsze wrócić 0. Jeśli oczekujesz Nones jako wartości, musisz to zrobić if key in d:jawnie.
Tim Pietzcker,
1
@cib na zdrowie, nie mogłem rozgryźć, co robiłem źle tutaj.
wobbily_col
@TimPietzcker - czy możesz wyjaśnić swoją odpowiedź? d.get (klucz) lub „pusty” w przypadku mapowania klucza na dowolną wartość „fałsz” jest „pusty”, jeśli się nie mylę.
MiloMinderbinder,
@MiloMinderbinder: "empty"jest zwracany, jeśli keynie jest prawidłowym kluczem d. Nie ma to nic wspólnego z keymapowaniem wartości .
Tim Pietzcker,
63

Nic dziwnego, że już nie. Jest wbudowany w język.

    >>> pomoc (dyktando)

    Pomoc na temat dyktowania klas we wbudowanych modułach:

    klasa dict (obiekt)
     | dict () -> nowy pusty słownik
     | dict (mapowanie) -> nowy słownik zainicjowany z obiektu mapującego
     | pary (klucz, wartość)
    ...
     |  
     | dostać(...)
     | D.get (k [, d]) -> D [k] jeśli k w D, w innym przypadku d domyślnie ustawiony na Brak.
     |  
    ...
John La Rooy
źródło
22

Posługiwać się dict.get

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

Daenyth
źródło
19

Powinieneś użyć get()metody z dictklasy

d = {}
r = d.get('missing_key', None)

Spowoduje to r == None. Jeśli klucz nie zostanie znaleziony w słowniku, funkcja get zwraca drugi argument.

dusktreader
źródło
19
Nie musisz podawać Nonejawnie. Jest to ustawienie domyślne.
Björn Pollex
18

Jeśli potrzebujesz bardziej przejrzystego rozwiązania, możesz podklasę dictuzyskać w ten sposób:

class NoneDict(dict):
    def __getitem__(self, key):
        return dict.get(self, key)

>>> foo = NoneDict([(1,"asdf"), (2,"qwerty")])
>>> foo[1]
'asdf'
>>> foo[2]
'qwerty'
>>> foo[3] is None
True
Björn Pollex
źródło
2
@marineau: Jak wspomniałem w komentarzu do innej odpowiedzi, problem defaultdictpolega na tym, że będzie on wzrastał za każdym razem, gdy pojawi się element, którego jeszcze nie ma. Nie zawsze jest to pożądane.
Björn Pollex,
@ BjörnPollex To jest zdecydowanie elegancki. Masz jakiś pomysł, jak go rozszerzyć, aby obsługiwał dowolną głębokość? Mam na myśli co foo['bar']['test']['sss']do powrotu Nonezamiast wyjątku Po jednej głębokości rozpocząć podając TypeErrorzamiastKeyError
nehem
@itsneo. Możesz zbudować całą strukturę NoneDicts. Pomogłoby to w przypadku, KeyErrorgdyby zdarzyło się to w najbardziej wewnętrznym obiekcie. W przeciwnym razie problem polega na tym, że po zwróceniu Noneobiektu nie można go już subskrybować. Jeden brzydki hack polegałby na zwróceniu innego obiektu, który jest testowany None. Uważaj jednak, że może to prowadzić do okropnych błędów.
magu_
@ BjörnPollex Czy można zmienić return dict.get(self, key)na return super().get(key)? Jeśli więc zdecyduję się na przykład użyć polecenia OrdersDict zamiast dykta, nie muszę się martwić o zmianę wielu wierszy kodu.
Wood
@Wood Tak, to byłoby o wiele milsze!
Björn Pollex
12

Zwykle używam defaultdict w takich sytuacjach. Podajesz metodę fabryczną, która nie przyjmuje argumentów i tworzy wartość, gdy widzi nowy klucz. Jest to bardziej przydatne, gdy chcesz zwrócić coś w rodzaju pustej listy nowych kluczy ( patrz przykłady ).

from collections import defaultdict
d = defaultdict(lambda: None)
print d['new_key']  # prints 'None'
praca
źródło
19
Problem defaultdictpolega na tym, że będzie się powiększał za każdym razem, gdy żądany będzie nieistniejący element.
Björn Pollex,
8

Możesz użyć metody dictobiektu get(), jak już sugerowali inni. Alternatywnie, w zależności od tego, co dokładnie robisz, możesz użyć takiego try/exceptpakietu:

try:
   <to do something with d[key]>
except KeyError:
   <deal with it not being there>

Co jest uważane za bardzo „pytoniczne” podejście do obsługi sprawy.

martineau
źródło
7

Rozwiązaniem jedno-liniowym byłoby:

item['key'] if 'key' in item else None

Jest to przydatne, gdy próbujesz dodać wartości słownika do nowej listy i chcesz podać wartość domyślną:

na przykład.

row = [item['key'] if 'key' in item else 'default_value']
imapotatoe123
źródło
5

Jak powiedzieli inni powyżej, możesz użyć get ().

Ale aby sprawdzić klucz, możesz także:

d = {}
if 'keyname' in d:

    # d['keyname'] exists
    pass

else:

    # d['keyname'] does not exist
    pass
Marek P.
źródło
Teraz widzę, że już wiesz, jak to zrobić. Chciałem usunąć swój post, ale zostawię go do wglądu innym.
Marek P,
4
Podejście to zwykle wymaga dwukrotnie sprawdzenia klucza, gdy jest on obecny, co prawdopodobnie jest przyczyną tej getmetody.
martineau
0

Byłem zaskoczony tym, co było możliwe w python2 vs python3. Odpowiem na to w oparciu o to, co skończyłem dla Python3. Mój cel był prosty: sprawdź, czy odpowiedź JSON w formacie słownika dała błąd, czy nie. Mój słownik nazywa się „tokenem”, a kluczem, którego szukam, jest „błąd”. Szukam klucza „błąd”, a jeśli go nie było, to ustawiam go na wartość Brak, wówczas sprawdzanie jest wartością Brak, jeśli tak, kontynuuj z moim kodem. Instrukcja else poradziłaby sobie, jeśli mam klucz „błąd”.

if ((token.get('error', None)) is None):
    do something
FastGTR
źródło
-2

Jeśli możesz to zrobić False, to jest też wbudowana funkcja hasattr :

e=dict()
hasattr(e, 'message'):
>>> False
Evhz
źródło