Late initialization using __getattribute__

bukzor workitharder at gmail.com
Wed Sep 3 17:46:00 EDT 2008


On Sep 3, 12:19 pm, Bruno Desthuilliers
<bdesth.quelquech... at free.quelquepart.fr> wrote:
> bukzor a écrit :
>
> > I want to make a MixIn class that waits to initialize its super-
> > classes until an attribute of the object is accessed. Not generally
> > useful, but desirable in my case. I've written this, and it works, but
> > would like to take any suggestions you guys have.
>
> You shouldn't mess with __getattribute__ unless you really know what
> you're doing and are ok to suffer the constant performance hit you'll
> get. Remember that __getattribute__ actually *is* the implementation of
> attribute lookup rules, and is called on each and every attribute
> lookup. Your below snippet would be much better using __getattr__ (which
> is only called as a last resort).
>
> > I've commented out
> > the "delattr" call because it throws an AttributeError (although I
> > don't know why).
>
> __getattribute__ belongs to the class, not to the instance. delattr()
> only removes instance attributes. You'd have to remove __getattribute__
> from the LateInitMixIn class object itself, but then it would break the
> whole thing.
>
>
>
> > class LateInitMixIn(object):
> >     def __init__(self):
> >         print "LateInit initialization"
> >         self.inited = False
> >     def __getattribute__(self, attr):
> >         print "Doing __getattribute__"
> >         getattr = lambda attr:object.__getattribute__(self, attr)
> >         if not getattr("inited"):
> >             super(LateInitMixIn, self).__init__()
> >             setattr(self, "inited", True)
> >         #delattr(self, "__getattribute__")
> >         return getattr(attr)
>
> Here's another possible implementation (which doesn't solve all
> problems, cf below) using __getattr__:
>
> class LateInitMixin(object):
>      def __init__(self):
>          print "not yet"
>          self.__initialized = False
>
>      def __getattr__(self, name):
>          if self.__initialized:
>              raise AttributeError(
>                  "object %s has no attribute '%s'" % (type(self), name)
>                  )
>          super(LateInitMixin, self).__init__()
>          self.__initialized = True
>          return getattr(self, name)
>
> class Base(object):
>      def __init__(self):
>          print "yet"
>          self.base = True
>
> class LateInit(LateInitMixin, Base):
>      pass
>
> def main():
>      print "shouldn't init"
>      S = LateInit()
>      print "should init"
>      print S.base
>
> if __name__=="__main__":
>      main()
>
> Ok, now, the other problem : what if Base.__init__ expects args ?

Thanks for the reply. Just to see it not work, I tried to remove
__getattribute__ from LateInitMixIn, but couldn't get it to work.

My Base class is a C class (_mysql.connection from MySQLdb) that
sometimes segfaults if you try to use it before it's fully
initialized, so unfortunately I think I need to use __getattribute__
to do this. I'm doing all this just to make the connection not
actually connect until used.



More information about the Python-list mailing list