Just wanted to show the end result in its actual implementation! I ended up *not* making a decorator, as I already had a good idea about how to do it using __getattr__
class PayloadDualFrqIQOnDemand(PayloadDualFrqIQ): """ This class has the same interface as its parent, but unlike its parent, it is instantiated without its payload parsed up in its instance attributes Q1, I1, Q2 and I2. Instead it stores a reference to the file object in which the Payload data can be read, the file position and the version of the payload data. On accessing one of the data attributes, the actual payload data are read from the file, and the reference to the file object is unbound. The constructor signature is therefore different from its parent as it takes the file object, position and version as arguments instead of the actual data. """ @classmethod def _unpack_from_file(cls, f, samples, ver): bytes = samples * cls.bytes_per_sample initial_pos = f.tell() f.seek(initial_pos + bytes) #Skip over the payload return cls(f, initial_pos, samples, ver) @classmethod def unpack_from_ver3_file(cls, f, samples): return cls._unpack_from_file(f, samples, ver=3) @classmethod def unpack_from_ver4_file(cls, f, samples): return cls._unpack_from_file(f, samples, ver=4) data_attr_names = frozenset(["Q1", "I1", "Q2", "I2"]) def __init__(self, a_file, a_file_position, samples, a_version): """ Returns an instance where the object knows where to look for the payload but it will only be loaded on the first attempt to read one of the data attributes in a "normal" PayloadDualFrqIQ object. """ self.f = a_file self.file_position = a_file_position self.samples = samples self.ver = a_version def __getattr__(self, attr_name): """ Checks if a request to read a non-existing data attribute has an attribute corresponding to one of the data attributes in a normal PayloadDualFrqIQ object. If true, the data attributes are created and bound to the object using the file object instance, the file position and the version. It is a prerequisite that the file object is still open. The function leaves the file object at the file position when it entered the method """ cls = self.__class__ if attr_name in cls.data_attr_names: initial_pos = self.f.tell() try: bytes = self.samples * cls.bytes_per_sample self.f.seek(self.file_position) buf = self.f.read(bytes) if self.ver == 3: bytes_to_data = cls._v3_byte_str_to_data elif self.ver == 4: bytes_to_data = cls._v4_byte_str_to_data else: raise TermaNotImplemented, \ "Support for ver. %d not implemented." % self.ver I1, Q1, I2, Q2 = bytes_to_data(buf) self.__dict__["I1"] = I1 self.__dict__["Q1"] = Q1 self.__dict__["I2"] = I2 self.__dict__["Q2"] = Q2 return self.__dict__[attr_name] finally: # Restore file position self.f.seek(initial_pos) # Unbind lazy attributes del self.f del self.ver del self.file_position del self.samples This seems to work out well. No infinite loops in __getattr__! At least it passes the unit test cases I have come up with so far. No guarantees though, as I may simply not have been smart enough to bring forth unit test cases which make it crash. Comments on the code is still appreciated though. I am still a novice Python programmer, and I may have overlooked more Pythonic ways to do it. -- Slaunger -- http://mail.python.org/mailman/listinfo/python-list