How to instantiate in a lazy way?

Nick Craig-Wood nick at craig-wood.com
Mon Dec 1 10:30:44 EST 2008


Slaunger <Slaunger at gmail.com> wrote:
>  Slaunger wrote:
> >
> > class PayloadOnDemand(object):
> > ? ? """
> > ? ? Behaves as a PayloadInstant object, but instantiation is faster
> > ? ? as only the position of the payload in the file is stored
> >     initially in the object.
> > ? ? Only when acessing the initially non-existing data attribute
> > ? ? are the data actually read and the attribure created and bound to
> >     the instance.
> > ? ? This will actually be a little slower than in PayloadInstant as
> >     the correct file position
> > ? ? has to be seeked out first.
> > ? ? On later calls the object has as efficient attribute access as
> >     PayloadInstant
> > ? ? """
> >
> > ? ? @classmethod
> > ? ? def read_from_file(cls, f, size):
> > ? ? ? ? pos = f.tell()
> > ? ? ? ? f.seek(pos + size) #Skip to end of payload
> > ? ? ? ? return cls(pos)
> 
>  Extend with ref to file instead:
>            return cls(f, pos)
> >
> > ? ? # I probably need some __getattr__ or __getattribute__ magic
> >     # there...??
> 
>  To answer my own rethorical question I guess I should do something
>  like this
> 
>      def __getattr__(self, attr_name):
>          """
>          Only called if attr_name is not in the __dict__ for the
>  instance
>          """
>          if attr_name == 'data':
>              self.__dict__[attr_name] = read_data(self.f,
>  self.file_position)
> 
> >
> > ? ? def __init__(self, a_file_position):
> > ? ? ? ? self.file_position = a_file_position
> >
>  and then I need to also store a reference to the file in the
>  constructor...
> 
>      def __init__(self, a_file, a_file_position):
>          self.f = a_file
>          self.file_position = a_file_position
> 
>  Have I understood correctly how to to it the on demand way?

I wouldn't use __getattr__ unless you've got lots of attributes to
overload.  __getattr__ is a recipe for getting yourself into trouble
in my experience ;-)

Just do it like this...

class PayloadOnDemand(object):
      def __init__(self, a_file, a_file_position):
          self._data = None
          self.f = a_file
          self.file_position = a_file_position

      @property
      def data(self):
          if self._data is None:
              self._data = self.really_read_the_data()
          return self._data

then you'll have a .data attribute which when you read it for the
first time it will populate itself.

If None is a valid value for data then make a sentinel, eg

class PayloadOnDemand(object):
      sentinel = object()

      def __init__(self, a_file, a_file_position):
          self._data = self.sentinel
          self.f = a_file
          self.file_position = a_file_position

      @property
      def data(self):
          if self._data is self.sentinel:
              self._data = self.really_read_the_data()
          return self._data


-- 
Nick Craig-Wood <nick at craig-wood.com> -- http://www.craig-wood.com/nick



More information about the Python-list mailing list