11
\$\begingroup\$

Let's say I have a key 'messages' that is usually a list, but might be None, or might not be present. So these are all valid inputs:

{
   'date': 'tuesday',
   'messages': None,
}

{
   'date': 'tuesday',
   'messages': ['a', 'b'],
}

{
   'date': 'tuesday',
}

If I want to retrieve 'messages' from the input, and iterate over them, I need to do something like this:

messages = d.get('messages', []) # Check for key existence
if messages is None:             # Check if key is there, but None
    messages = []
for message in messages:
    do_something()

That seems a little verbose for Python - is there a simpler way to write that?

\$\endgroup\$

closed as off-topic by Jamal Jul 27 '15 at 21:57

This question appears to be off-topic. The users who voted to close gave this specific reason:

If this question can be reworded to fit the rules in the help center, please edit the question.

  • 1
    \$\begingroup\$ Consider using a collections.defaultdict. \$\endgroup\$ – Jeff Mercado Apr 25 '13 at 8:32
12
\$\begingroup\$
for message in d.get('messages') or ():
    do_something()
  • get returns None by default for missing keys.
  • a or b evaluates to b when bool(a) == False. An empty list and None are examples of values that are false in a boolean context.
  • Note that you cannot use this trick if you intend to modify the possibly empty list that is already in the dict. I'm using () instead of [] to guard against such mistakes. Also, CPython caches the empty tuple, so using it is slightly faster than constructing an empty list.
\$\endgroup\$
  • 3
    \$\begingroup\$ Rollback: someone edited this to for message in d.get('messages', ()):. That would not, however, work when the value is None, like in the first example. \$\endgroup\$ – Janne Karila Oct 23 '13 at 6:50
2
\$\begingroup\$

You have to check for the existence of 'messages' AND the content of 'messages'. It's the same thing you have, but I would write it as:

if 'messages' in d and d['messages'] is not None:
    for m in d['messages']:
        do_something(m)
\$\endgroup\$
2
\$\begingroup\$

First of all, I'm no python guy and I always favor readability over one-liners. If this happens regularly I would implement a get method which will return the default value not only for missing keys, but also for empty (or what ever required) values.

In addition to that you maybe should have a look at the method that is generating your dictionary. Maybe you can just unify the message parameter at the place you store it and so you don't have to take care of this later?

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.