ActiveState Code

Recipe 496910: easy file parsing


This is useful for making easy and human to write definition files for whatever use. For example, lets say you are writing a simulator and you need an easy, human way to define parts about a given world like light sources, obstacles, and dimensions. see the discussion for this example fleshed out in code.

Python
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#parse a python file in a given environment, and get out some results
from os import dirname

def parseFile(filename, envin, envout = {}):
	exec "from sys import path" in envin
	exec "path.append(\"" + dirname(filename) + "\")" in envin
	envin.pop("path")
	lines = open(filename, 'r').read()
	exec lines in envin
	returndict = {}
	for key in envout:
		returndict[key] = envin[key]
	return returndict

Discussion

For the example above, You might write something like the following:

from parsefile import parseFile

class World:

    def dimensions(self, width, height):
        self.width = width
        self.height = height

    def __init__(self, filename):
        self.lightsources = []
        self.obstacles = []
        envin = {}
        envin['dimensions'] = self.dimensions
        envin['newobstacle'] = lambda x,y: self.obstacles.append((x,y))
        envin['newlightsource'] = lambda x,y: self.lightsources.append((x,y))
        parseFile(filename, envin)

If you were to then call something like World(file) in the runtime of your program where file is as follows:

#

dimensions(4, 5) newlightsource(1, 2) newlightsource(2, 3) newobstacle(0, 1)

#

You will end up with an instance of class World with the appropriate data, thus it is simple to create new ways to specify data for your program

Comments

  1. 1. At 7:06 a.m. on 27 jul 2006, N N said:

    Oh my.

    lines = open(filename, 'r').readlines()
    total = ""
    for line in lines:
        total += line
    

    Is a rather long way to spell:

    total=open(filename,'r').read()
    
  2. 2. At 6:16 p.m. on 31 jul 2006, Michael Haimes (the author) said:

    very true.. fortunately, it would only eat up a humanly unidentifiable amount of processor time unless the file was a ridiculous length. I made the change though

  3. 3. At 7:11 a.m. on 18 sep 2006, Ilan Copelyn said:

    Can't get this example working. Sorry - I'm new to Python.

    I get:-

        envin['dimensions'] = dimensions
    NameError: global name 'dimensions' is not defined
    

    And if i change the line so the function name "dimensions" is qualified by the class "World", then I get problems when trying to exec the text read from the file.txt:-

        exec lines in envin
      File "", line 2, in ?
    TypeError: unbound method dimensions() must be called with World instance as first argument (got int instance instead)
    

    BTW I'm using Python 2.4

  4. 4. At 11:30 a.m. on 18 sep 2006, Michael Haimes (the author) said:

    again, a typo on my end. It should have been self.dimensions instead of dimensions

    the dimensions method is indeed a method of the class World, but Python doesn't have static methods like java. Plus, this method needs an instance of world in order to edit instance data like width and height.

    the self keyword in Python is equivalent to the this keyword in Java, and just refers to the instance of the class that the method was called in.

  5. 5. At 4:49 a.m. on 21 sep 2006, Ilan Copelyn said:

    Thanks. that did the trick cheers

Sign in to comment