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