I'm using pyparsing to construct dictionaries that get appended to a list. When I do this the dictionaries get wrapped in an extra list and there is also an empty dict appended. I have no clue how to fix this. What I want is [{},{},{}]
. I am getting [([{}],{})]
Why the code from getDict give me what I want and not getDictParse?
#! /usr/bin/env python
from pyparsing import Literal, NotAny, Word, printables, Optional, Each, Combine, delimitedList, printables, alphanums, nums, White, OneOrMore, Group
noParseList = []
parseList = []
def getDict():
return {'duck':'moose','cow':'ewe'}
def getDictParse(str, loc, toks):
return {'duck2':toks[0],'cow2':'ewe'}
parser = Word(alphanums)
parser.setParseAction(getDictParse)
parseList.append(parser.parseString("monkey"))
noParseList.append(getDict())
print noParseList
print parseList
Outputs:
[{'cow': 'ewe', 'duck': 'moose'}]
[([{'cow2': 'ewe', 'duck2': 'monkey'}], {})]
In Python, just because something looks like a list containing a list and a dict, doesn't mean that's what it is. Python objects implement a __repr__
method that will display an informative string, but this is sometimes misleading. In the case of pyparsing, the parseString method returns an object of type ParseResults. ParseResults can have behavior like both lists and dicts, so when you print one out, it prints this tuple:
(list of matched tokens, dict of named tokens)
If you use list indexing (using an integer or slice notation), then the ParseResults __getitem__
method will index into the list of matched tokens. If you use key indexing (using a non-integer key), the ParseResults __getitem__
method will use the key on the dict of named tokens to return the value associated with that name, regardless of position. If the key would be a valid Python identifier, then you can even use object attribute accessing - in this case, the ParseResults __getattr__
method will use the key to index into the dict of named tokens also, but with a difference: in the event of a KeyError, using object attribute syntax will give you an empty string ''. Here is a more detailed example, follow the comments for descriptions of the different options:
from pyparsing import *
# define an integer token, and a parse-time conversion function
def cvtInteger(tokens):
return int(tokens[0])
integer = Word(nums).setParseAction(cvtInteger)
# define an animal type, with optional plural 's'
animal = Combine(oneOf("dog cat monkey duck llama") + Optional("s"))
# define an expression for some number of animals
# assign results names 'qty' and 'animal' for named access
# to parsed data tokens
inventoryItem = integer("qty") + animal("animal")
# some test cases
items = """\
7 llamas
1 duck
3 dogs
14 monkeys""".splitlines()
for item in items:
info = inventoryItem.parseString(item)
# print the parsed item
print type(info), repr(info)
# use string key to access dict item
print info['qty']
# use object attribute to access dict item
print info.animal
# use list indexing to access items in list
print info[-1]
# use object attribute to access
print info.average_weight
Prints:
<class 'pyparsing.ParseResults'> ([7, 'llamas'], {'animal': [('llamas', 1)], 'qty': [(7, 0)]})
7
llamas
llamas
<class 'pyparsing.ParseResults'> ([1, 'duck'], {'animal': [('duck', 1)], 'qty': [(1, 0)]})
1
duck
duck
<class 'pyparsing.ParseResults'> ([3, 'dogs'], {'animal': [('dogs', 1)], 'qty': [(3, 0)]})
3
dogs
dogs
<class 'pyparsing.ParseResults'> ([14, 'monkeys'], {'animal': [('monkeys', 1)], 'qty': [(14, 0)]})
14
monkeys
monkeys
So to answer your original question, you should be able to use the list access semantics to get at the dict returned by your parse action:
parseList.append(parser.parseString("monkey")[0])