Late initialization using __getattribute__

Bruno Desthuilliers bdesth.quelquechose at free.quelquepart.fr
Wed Sep 3 21:19:30 CEST 2008


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 ?




More information about the Python-list mailing list