2

My question is similar to Python dict how to create key or append an element to key?

I want to create the following dictionary of dictionaries:

my_dict = {
 "name1" : { "id1" : "pin1", "id2" : "pin2" },
 "name2" : { "id3" : "pin3", "id4" : "pin4" }
}

I currently accomplish this using the following:

if name in my_dict:
    my_dict[name].update({ id : pin }
else:
    my_dict[name] = { id : pin }

Is there a way to do this using dict.setdefault() ?

crusarovid
  • 501
  • 1
  • 5
  • 17

2 Answers2

8

Is there a way to do this using dict.setdefault() ?

Of course! There's nothing magic about setdefault; it just returns my_dict[name] if it exists, or sets my_dict[name] = default and returns default if not.

Either way, what it returns is the (potentially new) dict in my_dict[name], so all you have to do is update it:

my_dict.setdefault(name, {})[id] = pin

Or, if you really like using update instead of just [] =:

my_dict.setdefault(name, {}).update({id: pin})

For example:

>>> my_dict.setdefault('name1', {})['id10']= 'pin10'
>>> my_dict.setdefault('name3', {})['id20']= 'pin20'
{'name1': {'id1': 'pin1', 'id10': 'pin10', 'id2': 'pin2'},
 'name2': {'id3': 'pin3', 'id4': 'pin4'},
 'name3': {'id20': 'pin20'}}

More generally, you could obviously rewrite your existing code to this:

if name not in my_dict:
    my_dict[name] = {}
my_dict[name].update({ id : pin }

Whenever you can do that, you can use setdefault. (But notice that we're calling a mutating method or assigning to a key/index/member of my_dict[name] here, not just assigning a new value to my_dict[name]. That's the key to it being useful.)


Of course almost any time you can use setdefault, you can also use defaultdict (as demonstrated in CoryKramer's answer) (and vice-versa). If you want defaulting behavior all the time, use defaultdict. Only use setdefault if you want defaulting behavior just this once (e.g., you want defaulting while building the dict up, but you want KeyErrors later when using it).

abarnert
  • 354,177
  • 51
  • 601
  • 671
3

You can use collections.defaultdict

>>> from collections import defaultdict
>>> my_dict = defaultdict(dict)
>>> my_dict
defaultdict(<class 'dict'>, {})
>>> my_dict['name1'].update({'id1': 'pin1'})
>>> my_dict
defaultdict(<class 'dict'>, {'name1': {'id1': 'pin1'}})

Then you don't need the if statement, you can directly call update, and if no dict yet exists for that name a new one will be created before calling update

Cory Kramer
  • 114,268
  • 16
  • 167
  • 218