Raising Errors in __init__

Ken Ramsey kramsey at nvl.army.mil
Tue Oct 2 14:24:52 EDT 2001


Hello,

Running Python2.1 on Solaris, I've come accross a problem, which I've
solved, but I don't quite understand. My program suffered a small
memory leak problem, which became critial when I went to process huge
amounts of data. I carefully checked for cross references and cyclical
data structures until I was sure there were none, yet still the
problem remained. Watching my memory footprint grow as the program
ran, I realized that footprint only grew whenever an exception was
thrown during the __init__() function of a certain class. So, I
changed the __init__() function, having it simply set state variables,
and created an init2() function to actually operate on them.
Magically, not only did my memory leak disappear but the initial size
of my program shrank too. Following is a very basic outline of part of
the program. It is for doing statistical analysis of imagery. There is
a main image class, called aImage, and it serves in part as a
container class for a list of regions of interest, or ROIs:

ImageError = "ImageError"
RoiError = "RoiError"

class LeakPlugger:
    def __del__(self):
        for key in self.__dict__.keys():
            self.__dict__[key] = None

class aImage(LeakPlugger):
    def __init__(self, filename):
        self.filename = filename
        self.roiList = []
        LeakPlugger.__init__(self)
#   def init2()
        self.fp = open(filename, 'rb')
        # ... read the file to assign things like width, height,
pixels, etc.
        # to self.width, self.height, self.pixels, etc.
        for i in range(100):
            try:
                self.roiList.append(self.getRandomRoi())
            except RoiError, msg:
                sys.stderr.write("%s: %s\n" % (RoiError, msg))
                continue

    def getRandomRoi(self):
        # excerpted ... set up randomizer, get random coords
        return ROI(randomX, randomY, roiWidth, roiHeight, self.width,
                   self.height)

    def __del__(self):
        self.fp.close()
        LeakPlugger.__del__(self)

class ROI(LeakPlugger):
    def __init__(self, x, y, w, h, imW, imH):
        LeakPlugger.__init__(self)
        if (x+w) > imW or (y+h) > imH:
            raise RoiError, "ROI doesn't fit on image"
        self.x, self.y, self.w, self.h = x, y, w, h
        
if __name__ == '__main__':
    import os
    dir = "/images"
    filenames = os.listdir(dir)
    for file in filenames:
        image = aImage(os.path.join(dir, file))
#       image.init2()
        # do statistical stuff

Again, when the exception is thrown in aImage's __init__, the process
grows. Uncommenting the init2() eliminates this problem and shrinks
the process size, too. Anybody else encounter such problems? If so,
what's the skinny? Is it good policy to limit the actions of Python's
__init__ function to simple things, saving real work for helper
functions?

Thanks,

Ken Ramsey
eoir-measurements
kramsey at nvl.army.mil



More information about the Python-list mailing list