comp.lang.python question

The tarball with the code is here.

Run the code with nosetests -s

Copy of message posted:


Could you please give me some advice on the piece of code I am writing?

My system has several possible outputs, some of them are not always needed. I started 
to get confused with the code flow conditions needed to avoid doing unnecessary work. So 
I am trying to restructure it using lazy evaluation.

In the new mechanism I am coding I have a repository with two types of objects: infos and 
routines. In the begining I have a list of routines. Each routine tells which infos it can 
compute. In the example below I have 3 routines

Routine "ReadData" computes info "gender" and info "birth_year"
Routine "YearToAge" computes info "age" (using info "birth_year")
Routine "ComputeMHF" computes info "max_heart_frequency" (using info "gender" and info 

           /--> gender ----------------------------\
ReadData --|                                       | --> ComputeMHF --> max_heart_frequency
           \--> birth_year --> YearToAge --> age --/

So for instance if I all I need is info "age" only the routines "ReadData" and "YearToAge" are 

The code below implements the example. There are 3 files:
  - the test case for the example
  - the routines (classes) of the example
  - the lazy evaluation mechanism (independent of the example)

My questions are:
- Is there a more standard (pythonic) way to do what I am trying to do? Are there libraries, 
design patterns, functional programming structures to use to achieve what I am looking for (i.e 
am I trying to reinvent the wheel)?
- Is the coding style good?
- Can I avoid the eval command in Repository.add_routine? What I want there is to be able to 
collect routines from several files and having a generic repository code that ignores where these 
routines are.

Note: The routines do not need to declare the info they depend on. They request the info in the 
computation phase.
import unittest
from repository import Repository

ReadData routines
YearToAge routines
ComputeMHF routines

class Test(unittest.TestCase):

    def test_age(self):
        repo = Repository(ROUTINE_LIST)
        self.assertEqual(repo['age'], 30)

    def test_max_heart_frequency(self):
        repo = Repository(ROUTINE_LIST)
        self.assertEqual(repo['max_heart_frequency'], 181)
from repository import AbstractRoutine

class ReadData(AbstractRoutine):
    def __init__(self):
        super(ReadData, self).__init__(self.__class__.__name__,
                                       ['birth_year', 'gender'])
    def compute(self, repo):
        repo['birth_year'] = 1979
        repo['gender'] = 'F'

class YearToAge(AbstractRoutine):
    def __init__(self):
        super(YearToAge, self).__init__(self.__class__.__name__,
    def compute(self, repo):
        repo['age'] = 2009 - repo['birth_year']

class ComputeMHF(AbstractRoutine):
    def __init__(self):
        super(ComputeMHF, self).__init__(self.__class__.__name__,
    def compute(self, repo):
        gender = repo['gender']
        age = repo['age']
        mhf = 211 - age if gender == 'F' else 205 - age
        repo['max_heart_frequency'] = mhf
from StringIO import StringIO

class AbstractRoutine(object):

    def __init__(self, name, infos_provided): = name
        self.infos_provided = infos_provided
        self.computed = False

    def compute(self):
        raise NotImplementedError

class Info(object):
    def __init__(self, name, routine): = name
        self.routine = routine
        self.computed = False
        self.value = None

class Repository(object):

    def __init__(self, routine_definition_lines):
        self._infos = {}

    def add_routines(self, definition_lines):
        for line in StringIO(definition_lines):
            line = line.strip()
            if line == '':
            name, file_name = line.split()
            self.add_routine(name, file_name)

    def add_routine(self, class_name, file_name):
        routine = None  # only to cheat pylint
        cmd = "from %s import %s\nroutine = %s()" % (file_name,
        exec(cmd)  # XXX: ugly
        if not isinstance(routine, AbstractRoutine):
            raise ValueError('Class %s is not AbstractRoutine'
                             % class_name)
        for info_name in routine.infos_provided:
            info = Info(info_name, routine)
            self._infos[info_name] = info

    def __setitem__(self, key, value):
        if key not in self._infos:
            raise ValueError('info %s not defined in repository' % key)
        info = self._infos[key]
        if info.computed:
            raise ValueError('info %s has already been computed' % key)
        info.value = value
        info.computed = True

    def __getitem__(self, key):
        if key not in self._infos:
            raise ValueError('info %s not defined in repository' % key)
        info = self._infos[key]
        if not info.computed:
            print('Calling routine %s to compute info %s'
                  % (,
            if not info.computed:           
                raise ValueError('routine %s did not compute info %s' %
                                 (, key))
        return info.value

Thanks a lot!
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License