Can dictionaries be nested?

T

techiepundit

I'm parsing some data of the form:

OuterName1 InnerName1=5,InnerName2=7,InnerName3=34;
OuterName2 InnerNameX=43,InnerNameY=67,InnerName3=21;
OuterName3 ....
and so on....

These are fake names I've made up to illustrate the point more clearly.

(the embedded device device can't produce XML and this is what I have
to deal with)

I want to populate a nested set of dictionaries where the outer most
dictionary has look-ups on the OuterNames:

InnerDict = OuterDict["OuterName2"]

Then InnerDict[InnerName3] would yield 21 in the above example.

First, can dictionaries contain dictionaries?

Second, how to create each successive inner dictionary when populating
it? Python doesn't have constructors and (having all of 4 weeks of
Python experience) it isn't clear to me whether in nested while loops
that variables ever go out of scope.

If I do:

OuterDict = {}
while populating dictionaries
InnerDict = {}
while inner stuff to populate
InnerDict["InnerName1"] = 5
.. and so on
:
OuterDict["OuterName1"] = InnerDict

then when I loop around the second time will the same InnerDict get
set back to an empty dictionary and therefore wipe out the dictionary I
put at OuterDict["OuterName1"] ?

I need a new inner dictionary each time thru the outer while loop. It
is not clear to me how to do this.
 
P

Paul Rubin

First, can dictionaries contain dictionaries?
Yes.

Second, how to create each successive inner dictionary when populating
it? Python doesn't have constructors and (having all of 4 weeks of
Python experience) it isn't clear to me whether in nested while loops
that variables ever go out of scope.

All variables stay in scope through the entire execution of the
function they're created in.
If I do:

OuterDict = {}
while populating dictionaries
InnerDict = {}
while inner stuff to populate
InnerDict["InnerName1"] = 5
.. and so on
:
OuterDict["OuterName1"] = InnerDict

then when I loop around the second time will the same InnerDict get
set back to an empty dictionary and therefore wipe out the dictionary I
put at OuterDict["OuterName1"] ?

It will get set to a newly created empty dictionary. The old
dictionary won't get wiped out, and will stay accessible through
OuterDict["OuterName1"].
I need a new inner dictionary each time thru the outer while loop. It
is not clear to me how to do this.

You've done it correctly. It's pretty easy to test this stuff by
experiment. You probably spent almost as much time posting to the
newsgroup as simply trying it would have taken:
people = {}
person = {}
person['age'] = 25
person['nationality'] = 'dutch'
people['john'] = person
people {'john': {'nationality': 'dutch', 'age': 25}}
person = {} # make new dictionary
people # hasn't changed {'john': {'nationality': 'dutch', 'age': 25}}
person['age'] = 3.6e25
person['nationality'] = 'cosmic'
people['FSM'] = person
people
{'john': {'nationality': 'dutch', 'age': 25},
'FSM': {'nationality': 'cosmic', 'age': 3.6000000000000002e+25}}
 
P

Paul McGuire

I'm parsing some data of the form:

OuterName1 InnerName1=5,InnerName2=7,InnerName3=34;
OuterName2 InnerNameX=43,InnerNameY=67,InnerName3=21;
OuterName3 ....
and so on....
I wrote pyparsing for just this kind of job. Using pyparsing, you can both
parse the data and build up structured results - even results with keyed
fields or dictionary-type access.

Here's the complete pyparsing program to parse your data:

---------------------------
data = """
OuterName1 InnerName1=5,InnerName2=7,InnerName3=34;
OuterName2 InnerNameX=43,InnerNameY=67,InnerName3=21;
"""
# or data = file(inputname).read()

from pyparsing import *

EQ = Literal("=").suppress()
SEMI = Literal(";").suppress()
ident = Word(alphas, alphanums+"_")
integer = Word(nums)

value = integer | quotedString

innerentry = Group(ident + EQ + value)

vallist = Dict(delimitedList(innerentry))
outerentry = Group(ident + vallist + SEMI)
datalist = Dict( ZeroOrMore(outerentry) )

vals = datalist.parseString(data)
print vals.keys()
print vals["OuterName1"]["InnerName2"]
print vals.OuterName2.InnerNameY

---------------------------

Prints:
['OuterName2', 'OuterName1']
7
67

Here's the same program, with a few more comments to explain what's going
on:
---------------------------
from pyparsing import *

# define expressions for some basic elements - use pyparsing's basic
# building blocks, Literal and Word
EQ = Literal("=").suppress()
SEMI = Literal(";").suppress()
ident = Word(alphas, alphanums+"_")
integer = Word(nums)

# expand this list to include other items you end up finding in values
value = integer | quotedString

# define the format of the list of InnerName entries
innerentry = Group(ident + EQ + value)

# delimitedList is a pyparsing helper for a list of expressions, separated
by
# some delimiter - default delimiter is a comma
vallist = delimitedList(innerentry)

# lastly, define the overall datalist
outerentry = Group(ident + vallist + SEMI)
datalist = ZeroOrMore( outerentry )

# extract the data into a structure using parseString
vals = datalist.parseString(data)

# prettyprint the results
import pprint
pprint.pprint(vals.asList())
print


# Refinement: have pyparsing build keyed results while
# it parses (accessible like a dict)
vallist = Dict(delimitedList(innerentry))
outerentry = Group(ident + vallist + SEMI)
datalist = Dict( ZeroOrMore(outerentry) )

# reparse using modified grammar
vals = datalist.parseString(data)

# view results using dict functions
print vals.keys()
print vals["OuterName1"]["InnerName2"]

# if keys are valid Python identifiers, can also access results
# like object fields
print vals.OuterName2.InnerNameY
---------------------------
Prints:

[['OuterName1',
['InnerName1', '5'],
['InnerName2', '7'],
['InnerName3', '34']],
['OuterName2',
['InnerNameX', '43'],
['InnerNameY', '67'],
['InnerName3', '21']]]

['OuterName2', 'OuterName1']
7
67

Download pyparsing at http://pyparsing.sourceforge.net. (I'm also making a
couple of pyparsing presentations at PyCon, next month.)

-- Paul
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top