one-time initialization of class members
Steven Bethard
steven.bethard at gmail.com
Wed Jun 13 23:42:36 EDT 2007
James Turk wrote:
> It actually occured to me that I could use a @classmethod to do the
> loading and take that out of the BaseClass constructor. What I have
> makes more sense and eliminates the unecessary constructors.
>
> ie.
>
> class BaseClass:
> @classmethod
> def loadData(params):
> #expensive load here
>
> class ChildClass1(BaseClass):
> dataset = BaseClass.loadData(params)
>
> This is pretty much along the lines of what you suggested, thank you
> for the hint in the right direction.
>
> I realized that this still doesn't meet my needs exactly as I only
> want the expensive dataset to be loaded if/when a class is actually
> used (there are potentially many of these and only a few will be
> used).
Seems like you want a lazy class attribute. How about something like::
>>> class LazyClassAttribute(object):
... def __init__(self, func):
... self.func = func
... def __get__(self, obj, cls=None):
... value = self.func(cls)
... setattr(cls, self.func.__name__, value)
... return value
...
>>> class Base(object):
... @LazyClassAttribute
... def dataset(cls):
... print 'calculating dataset'
... return 'dataset(%s)' % cls.params
...
>>> class Child1(Base):
... params = 'foo'
...
>>> class Child2(Base):
... params = 'bar'
...
>>> Child1.dataset
calculating dataset
'dataset(foo)'
>>> Child1.dataset
'dataset(foo)'
>>> Child2.dataset
calculating dataset
'dataset(bar)'
>>> Child2.dataset
'dataset(bar)'
The idea is basically similar to the @classmethod approach except that
instead of @classmethod, we use a custom descriptor that calls the
method the first time it's accessed and then stores that value
afterwards. This means that instead of explicitly calling the
@classmethod, the method will be called whenever the attribute is first
accessed.
STeVe
More information about the Python-list
mailing list