750

I need a way to get a dictionary value if its key exists, or simply return None, if it does not.

However, Python raises a KeyError exception if you search for a key that does not exist. I know that I can check for the key, but I am looking for something more explicit. Is there a way to just return None if the key does not exist?


See also: Why dict.get(key) instead of dict[key]?

Karl Knechtel
  • 62,466
  • 11
  • 102
  • 153
Spyros
  • 46,820
  • 25
  • 86
  • 129
  • 123
    Just use `.get(key)` instead of `[key]` – Gabe May 25 '11 at 20:51
  • 3
    Accessing the key and catching the exception is perfectly okay in Python. It is even a well known and oft-used design pattern. If you return None instead, it becomes impossible to store None as a value, which may be relevant in some cases. – Ber May 25 '11 at 22:00
  • 1
    Sometimes you want to treat "None" entries in the dictionary and missing entries the same, in that case the accepted answer seems to do the job just fine. – cib Jul 05 '15 at 17:02

15 Answers15

1251

You can use dict.get()

value = d.get(key)

which will return None if key is not in d. You can also provide a different default value that will be returned instead of None:

value = d.get(key, "empty")
Tim Pietzcker
  • 328,213
  • 58
  • 503
  • 561
  • 90
    Note that the second variant with a default fallback will still return `None` if the key is explicitly mapped to `None` in the dict. If that's not what you want, you can use something like `d.get(key) or "empty"`. – cib Jul 05 '15 at 17:07
  • 24
    @cib: Good point, but the solution has a similar problem - if the key is mapped to any "falsy" value (like `[]`, `""`, `False`, `0.0` or indeed `None`), then your solution would always return `0`. If you expect `None`s as values, you will have to do the `if key in d:` check explicitly. – Tim Pietzcker Jul 05 '15 at 17:57
  • 1
    @cib cheers for that, I couldn't work out what I was doing wrong here. – wobbily_col Aug 23 '16 at 14:28
  • @TimPietzcker - can you please explain your answer? d.get(key) or "empty" in case of key being mapped to any 'falsy' values is "empty" if i am not mistaken. – figs_and_nuts Sep 02 '19 at 15:06
  • @MiloMinderbinder: `"empty"` is returned if `key` is not a valid key in `d`. It has nothing to do with the value `key` is mapped to. – Tim Pietzcker Sep 02 '19 at 15:07
  • @TimPietzcker - d.get(key) or "empty" ... would that not return "empty" if key is present but the key is mapped to 0. (or any "falsy" value . like None,[]). example: a = {'a':0,'b':1} a['a'] or "empty" – figs_and_nuts Sep 03 '19 at 15:15
  • Ah, now I see what you meant. I didn't read your question carefully enough. I was looking at my answer (`d.get(key, "empty")`, which doesn't have that problem) instead of the `or` variant. – Tim Pietzcker Sep 03 '19 at 16:55
  • an example with the walrus would be cool ;) – Charlie Parker Nov 26 '21 at 20:21
71

Wonder no more. It's built into the language.

    >>> help(dict)

    Help on class dict in module builtins:

    class dict(object)
     |  dict() -> new empty dictionary
     |  dict(mapping) -> new dictionary initialized from a mapping object's
     |      (key, value) pairs
    ...
     |  
     |  get(...)
     |      D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.
     |  
    ...
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
35

Use dict.get

Returns the value for key if key is in the dictionary, else default. If default is not given, it defaults to None, so that this method never raises a KeyError.

RWC
  • 4,697
  • 2
  • 22
  • 29
Daenyth
  • 35,856
  • 13
  • 85
  • 124
35

You should use the get() method from the dict class

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

This will result in r == None. If the key isn't found in the dictionary, the get function returns the second argument.

Evhz
  • 8,852
  • 9
  • 51
  • 69
dusktreader
  • 3,845
  • 7
  • 30
  • 40
25

If you want a more transparent solution, you can subclass dict to get this behavior:

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
  • 75,346
  • 28
  • 201
  • 283
  • 2
    @marineau: As i mentioned in a comment to another answer, the problem with the `defaultdict` is that it will grow each time an element that is not yet in there is requested. This is not always desirable. – Björn Pollex May 25 '11 at 21:54
  • 2
    @BjörnPollex This is by far the elegant one, Any clue on how to extend this to support any depth? I mean making `foo['bar']['test']['sss']` to return `None` instead of exception, After one depth it start giving `TypeError` instead of `KeyError` – nehem Nov 10 '15 at 01:40
  • @itsneo. You could build the entire structure of `NoneDicts`. This would help in case the `KeyError` would happen in the innermost object. Otherwise the problem is, that once you return a `None` object you can't subscribe it anymore. One ugly hack would be to return another object that tests like `None`. Beware however that this could lead to horrible bugs. – magu_ Nov 18 '15 at 16:51
  • @BjörnPollex Is it okay to change `return dict.get(self, key)` to `return super().get(key)`? Then if I decide to use OrderedDict instead of dict, for example, I don't have to worry about changing multiple lines of code. – Wood Aug 23 '18 at 05:40
  • @Wood Yes, that would actually be much nicer! – Björn Pollex Aug 23 '18 at 06:43
  • What if we want to return a default value other than None? – sh37211 Jul 14 '23 at 23:14
  • @sh37211 then adjust the call to `.get` within the class, **in exactly the same way that you would** if following the other answers and calling `.get` directly. – Karl Knechtel Aug 24 '23 at 18:00
  • Arguably it would be better to implement this technique using `__missing__` rather than by overriding the `__getitem__` logic. That hook was explicitly provided for cases like this one. – Karl Knechtel Aug 24 '23 at 18:00
24

I usually use a defaultdict for situations like this. You supply a factory method that takes no arguments and creates a value when it sees a new key. It's more useful when you want to return something like an empty list on new keys (see the examples).

from collections import defaultdict
d = defaultdict(lambda: None)
print d['new_key']  # prints 'None'
Asclepius
  • 57,944
  • 17
  • 167
  • 143
job
  • 9,003
  • 7
  • 41
  • 50
  • 21
    The problem with the `defaultdict` is that it will keep growing each time a non-existing element is requested. – Björn Pollex May 25 '11 at 21:29
  • This can also be the desired behavior, like when you're trying to build a nested dict with a loop. – Dre Oct 27 '22 at 18:38
13

A one line solution would be:

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

This is useful when trying to add dictionary values to a new list and want to provide a default:

eg.

row = [item['key'] if 'key' in item else 'default_value']
imapotatoe123
  • 656
  • 1
  • 10
  • 21
  • That's a very intriguing approach. Thanks for adding this answer. I'll definitely explore this for a use-case. – Carewen Sep 17 '22 at 05:49
12

As others have said above, you can use get().

But to check for a key, you can also do:

d = {}
if 'keyname' in d:

    # d['keyname'] exists
    pass

else:

    # d['keyname'] does not exist
    pass
Marek P
  • 445
  • 3
  • 12
  • I now see that you already know how to do this. I was going to delete my post, but I'll leave it for reference for others. – Marek P May 25 '11 at 21:03
  • 4
    This approach usually requires the key to be looked-up twice when it's there, which is probably the reason for the `get` method. – martineau May 25 '11 at 21:57
10

You could use a dict object's get() method, as others have already suggested. Alternatively, depending on exactly what you're doing, you might be able use a try/except suite like this:

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

Which is considered to be a very "Pythonic" approach to handling the case.

martineau
  • 119,623
  • 25
  • 170
  • 301
  • I would argument that this would violate the "explicit instead of implicit" principle, and make the intent unclear. Not to mention the fragility and verbosity. – Haroldo_OK Apr 11 '22 at 10:22
  • @Haroldo_OK: I could not disagree more, it's very explicit. – martineau Apr 11 '22 at 12:03
  • I'm inclined to agree that this is actually a very explicit approach. While it does make for more lines of code (get() is effectively a single line), it IS very readable. – Carewen Sep 17 '22 at 05:48
3

For those using the dict.get technique for nested dictionaries, instead of explicitly checking for every level of the dictionary, or extending the dict class, you can set the default return value to an empty dictionary except for the out-most level. Here's an example:

my_dict = {'level_1': {
             'level_2': {
                  'level_3': 'more_data'
                  }
              }
           }
result = my_dict.get('level_1', {}).get('level_2', {}).get('level_3')
# result -> 'more_data'
none_result = my_dict.get('level_1', {}).get('what_level', {}).get('level_3')
# none_result -> None

WARNING: Please note that this technique only works if the expected key's value is a dictionary. If the key what_level did exist in the dictionary but its value was a string or integer etc., then it would've raised an AttributeError.

eaydin
  • 1,434
  • 1
  • 13
  • 11
0

I was thrown aback by what was possible in python2 vs python3. I will answer it based on what I ended up doing for python3. My objective was simple: check if a json response in dictionary format gave an error or not. My dictionary is called "token" and my key that I am looking for is "error". I am looking for key "error" and if it was not there setting it to value of None, then checking is the value is None, if so proceed with my code. An else statement would handle if I do have the key "error".

if ((token.get('error', None)) is None):
    do something
FastGTR
  • 343
  • 4
  • 4
0

You can use try-except block

try:
    value = dict['keyname']

except IndexError:
    value = None
Varmilo
  • 29
  • 3
0
  1. d1={"One":1,"Two":2,"Three":3}

  2. d1.get("Four")

If you will run this code there will be no 'Keyerror' which means you can use 'dict.get()' to avoid error and execute your code

Aditya
  • 19
  • 2
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 04 '22 at 09:51
0

If you have a more complex requirement that equates to a cache, this class might come in handy:

class Cache(dict):
    """ Provide a dictionary based cache

        Pass a function to the constructor that accepts a key and returns
        a value.  This function will be called exactly once for any key
        required of the cache.
    """

    def __init__(self, fn):
        super()
        self._fn = fn

    def __getitem__(self, key):
        try:
            return super().__getitem__(key)
        except KeyError:
            value = self[key] = self._fn(key)
            return value

The constructor takes a function that is called with the key and should return the value for the dictionary. This value is then stored and retrieved from the dictionary next time. Use it like this...

def get_from_database(name):
    # Do expensive thing to retrieve the value from somewhere
    return value

answer = Cache(get_from_database)
x = answer(42)   # Gets the value from the database
x = answer(42)   # Gets the value directly from the dictionary
Thickycat
  • 894
  • 6
  • 12
-5

If you can do it with False, then, there's also the hasattr built-in funtion:

e=dict()
hasattr(e, 'message'):
>>> False
Evhz
  • 8,852
  • 9
  • 51
  • 69