7

I am attempting to access a dictionary's values based on a list of keys I have. If the key is not present, I default to None. However, I am running into trouble when the value is an empty string ''. Please see the code below for my examples

dict = {}
dict['key'] = ''
test = dict.get('key')
print(test)
>>

Above is as expected, and the empty string is printed. But now see what happens when I default the dict.get() function to None if the key is not present

dict = {}
dict['key'] = ''
test = dict.get('key') or None
print(test)
>> None

Why does this happen? In the second example the key is present so my intuition says '' should be printed. How does Python apply the 'or' clause of that line of code?

Below is the actual code I'm using to access my dictionary. Note that many keys in the dictionary have '' as the value, hence my problem.

# build values list
params = []
for col in cols:
    params.append(dict.get(col) or None)

Is there a best solution someone can offer? My current solution is as follows but I don't think it's the cleanest option

# build values list
params = []
for col in cols:
    if dict.get(col) is not None:
        params.append(dict.get(col))
    else:
        params.append(None)
ProgrammingWithRandy
  • 725
  • 3
  • 14
  • 31
  • 1
    as for the first question, empty strings are falsy in python, so the second option for the `or` operator is printed – michele b May 11 '16 at 14:20
  • 3
    You can simply use `dict.get('key')`. `get` already returns None if it can't find the key. – DeepSpace May 11 '16 at 14:30
  • `if dict.get(col) is not None: ; else: ` Really? – Tadhg McDonald-Jensen May 11 '16 at 14:38
  • Yep that works, thank you. I disagree that it is a duplicate of the question linked as my question deals mostly with the behavior of the dict.get() function. Nonetheless glad this is solved. – ProgrammingWithRandy May 11 '16 at 14:49
  • 1
    To expand on @TadhgMcDonald-Jensen's comment, you really just want `for col in cols: params.append(dict.get(col))`. Or you could simplify further to make the code a one-liner with `params = [dict.get(col) for col in cols]`, or if `cols` is huge and you really need that last ounce of performance, `params = map(dict.get, cols)` (wrap the `map` call in `list` if you're on Python 3 and need `params` to be a true `list`, not a lazy generator that can be iterated exactly once and then discarded). Side-note: Don't name your `dict` "dict" (or any other built-in name); name shadowing is bad. – ShadowRanger May 11 '16 at 16:12

3 Answers3

20

You don't need or None at all. dict.get returns None by default when it can't find the provided key in the dictionary.

It's a good idea to consult the documentation in these cases:

get(key[, default])

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

Community
  • 1
  • 1
DeepSpace
  • 78,697
  • 11
  • 109
  • 154
6

You can simply use the second argument of get.

dict.get(col, None)

The second argument is the default for when it can't find the key. The or in that case takes the thing before the or if it is something, otherwise takes whatever is after the or.

Matthias Schreiber
  • 2,347
  • 1
  • 13
  • 20
  • 1
    Mind you, `dict.get(col, None)` is 100% identical to `dict.get(col)`; the `default` argument for `dict.get` is already `None`, so passing it explicitly doesn't change behavior at all. Also, it doesn't really address the problem, which is that empty strings are falsy. – ShadowRanger May 11 '16 at 14:29
  • The default for `.get`'s second argument is `None`, so OP needs neither the `or` nor to provide `None` as the second argument. – DeepSpace May 11 '16 at 14:29
1

The issue is that the empty string is not considered True in python. for example take a look at this code.

>>> x = 1 if "" else 0
>>> y = 1 if True else 0
>>> z = 1 if False else 0

The value of x and z will be 0 while the value for y will be 1.

dict.get() returns None by default

or by using a defaultdict

Jules
  • 973
  • 4
  • 10
  • 1
    `dict.get()` already returns `None` if the key isn't found, by default. – SiHa May 11 '16 at 14:28
  • 1
    this would be easier explained with `bool('') -> False` and a link to [the relevent documentation](https://docs.python.org/3.5/library/stdtypes.html#truth-value-testing) – Tadhg McDonald-Jensen May 11 '16 at 14:35