[Tutor] creating a nested dictionary

Remco Gerlich remco at gerlich.nl
Thu Jan 24 10:46:11 CET 2008


Hi,

Stream of consciousness answer:

So, you want to set things in a dictionary with a statement like
d[a][b][c][d] = x,
 even though d[a] wasn't used before so it's not initialized yet (let alone
d[a][b]).

Of course, if d is a dict, the d[a] = x works. That's one level deep, and
non existing keys are just created for you. More levels is harder.

In the collections module, there is a defaultdict object. You can tell it
what to use as a default for some value if it doesn't exist yet. Other than
that, it works as a normal dict.
Say, if we do:

from collections import defaultdict
d = defaultdict(dict)

Then, if you use d[a] when it doesn't exist yet, it will call dict() to
create a new dictionary.

So now d[a][b] = x works.

But d[a][b][c] = x still doesn't, since the newly created dictionary isn't
_itself_ a default dictionary - it's a normal dict.

Instead of 'dict', we need to give defaultdict a function that takes no
arguments and returns a defaultdictionary object. Like

d = defaultdict(lambda: defaultdict(dict))

Now d[a][b][c] = x works. But, again, the last one is a dict, so we still
can't go deeper...

Now of course d = defaultdict(lambda: defaultdict(lambda:
defaultdict(dict))) is there. It solves your problem; you can now set
d[a][b][c][d] = x.

(importantly, you shouldn't mix depths; don't first set d[a][b][c] = 3 and
then try to set d[a][b][c][d]; since d[a][b][c] won't be a dictionary
anymore).

I can't think of a really good generalization, one that will work for all
depths. That's the sort of thing you use Lisp, combinators and lots of
coffee for. Perhaps later today.

For now though:

def deep_default_dict(level):
   if level < 1:
      raise ValueError()
   result = dict
   while level > 1:
      result = lambda: defaultdict(result)
      level -= 1
   return result

d = deep_default_dict(4)()

Should give a dictionary for level=1 and the appropriate defaultdict for the
number of levels you need.

But I can't test right now...

Remco


On Jan 24, 2008 8:20 AM, Garry Willgoose <garry.willgoose at newcastle.edu.au>
wrote:

> Is there any easy way to create a nested dictionary. I want to be
> able to allocate like
>
> pdb[dataset][modulename][parametername]['value']=value
>
> where dataset, modulename, parametername are variables that are
> determined within loops nested 3 deep, and value comes from a
> database call. Prior to the nested loops I do not know what the
> values of dataset, modulename, parametername will range over, but I
> do know pdb needs to be nested 3 deep. What I'd like to do is
> something like this
>
> pdb={}
> for dataset in dataset_list:
>        modulename_list=getmodules(dataset)
>        for modulename in modulename_list:
>                parametername_list=getparameters(dataset,modulename)
>                for parametername in parametername_list:
>                        value=getvalue(dataset, modulename, parametername)
>
>  pdb[dataset][modulename][parametername]['value']=value
>
> What I'm currently doing is
>
> pdb={}
> for dataset in dataset_list:
>        modulename_list=getmodules(dataset)
>        moduledict={}
>        for modulename in modulename_list:
>                parametername_list=getparameters(dataset,modulename)
>                valuedict={}
>                for parametername in parametername_list:
>                        value=getvalue(dataset, modulename, parametername)
>                        valuedict['value']=value
> #  valuedict needs to be a dictionary because there is other stuff
>                        valuedict['otherstuff]=otherstuff
> ...
>                        parameterdict[parametername]=valuedict.copy()
>                moduledict[modeulename]=copy.deepcopy(parameterdict)
>        pdb[dataset]=copy.deepcopy(moduledict)
>
>
> Now I know the 2nd is not that much more complex but this is a pretty
> common construct in what I'm doing so I'm just wondering if there is
> a clear and simple shortcut ;-)
>
>
> ====================================================================
> Prof Garry Willgoose,
> Australian Professorial Fellow in Environmental Engineering,
> Director, Centre for Climate Impact Management (C2IM),
> School of Engineering, The University of Newcastle,
> Callaghan, 2308
> Australia.
>
> Centre webpage: www.c2im.org.au
>
> Phone: (International) +61 2 4921 6050 (Tues-Fri AM); +61 2 6545 9574
> (Fri PM-Mon)
> FAX: (International) +61 2 4921 6991 (Uni); +61 2 6545 9574 (personal
> and Telluric)
> Env. Engg. Secretary: (International) +61 2 4921 6042
>
> email:  garry.willgoose at newcastle.edu.au;
> g.willgoose at telluricresearch.com
> email-for-life: garry.willgoose at alum.mit.edu
> personal webpage: www.telluricresearch.com/garry
> ====================================================================
> "Do not go where the path may lead, go instead where there is no path
> and leave a trail"
>                           Ralph Waldo Emerson
> ====================================================================
>
>
>
>
>
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> http://mail.python.org/mailman/listinfo/tutor
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.python.org/pipermail/tutor/attachments/20080124/43dc5d4c/attachment-0001.htm 


More information about the Tutor mailing list