Computing class variable on demand?

Steven Bethard steven.bethard at gmail.com
Thu Feb 3 13:00:36 EST 2005


fortepianissimo wrote:
> This seems to be what I need. My use case is to do lengthy
> intialization as late as possible. In this case this is to initialize
> class variables. Does this make sense?

Yup.  If they definitely have to be class variables, then yeah, you 
probably need to use a metaclass.  If you're looking for late 
initialization, Scott David Daniels has a nice descriptor recipe for this:

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/363602

Probably this is a better call than using __getattr__.  With it, your 
code might look like[1]:

py> class LazyAttribute(object):
...     def __init__(self, calculate_function):
...         self._calculate = calculate_function
...     def __get__(self, obj, _=None):
...         if obj is None:
...             return self
...         value = self._calculate(obj)
...         setattr(obj, self._calculate.func_name, value)
...         return value
...
py> class Foo(object):
...     class __metaclass__(type):
...         @LazyAttribute
...         def bar(self):
...             print 'slow initialization'
...             return 'apple'
...
py> Foo.bar
slow initialization
'apple'
py> Foo.bar
'apple'

That way, you define all the attributes that need to be lazily 
initialized in the __metaclass__ class.  If all your classes will have 
the same lazily initialized attributes, you could also write this like:

py> class BarType(type):
...     @LazyAttribute
...     def bar(self):
...         print 'slow initialization'
...         return 'apple'
...
py> class Foo(object):
...     __metaclass__ = BarType
...
py> class Baz(object):
...     __metaclass__ = BarType
...
py> Foo.bar
slow initialization
'apple'
py> Foo.bar
'apple'
py> Baz.bar
slow initialization
'apple'
py> Baz.bar
'apple'

But I suspect the former is what you want...

Steve

[1] If you're using Python < 2.4, you'll have to make the decorator call 
manually, e.g.

     def bar(self):
        ...
     bar = LazyAttribute(bar)



More information about the Python-list mailing list