Computing class variable on demand?

Steven Bethard steven.bethard at gmail.com
Fri Feb 4 11:56:09 EST 2005


fortepianissimo wrote:
> Thank you so much about this useful tip! I learned the new decorator
> feature of 2.4 simply because of your post.
> 
> Unfortunately I don't have luxury right now to run Python 2.4 (for what
> I'm doing anyways). You mentioned the way to do decorator in 2.3. Still
> I have a question here. Here is Scott David Daniels's code for lazy
> initialization:
> 
> class Lazy (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
> 
> The problem I run into using this for *instance* variables is: the
> setattr() call won't work with a class with __slots__ defined - it
> simply produces error that the attribute we want to modify is
> read-only. Is there a workaround of this problem?

Sounds like you're declaring the class variables in your __slots__ too. 
  Is this true?  I don't think that's necessary -- __slots__ is only for 
used for instances.  So, for example, this code should work okay:

py> class Foo(object):
...     __slots__ = ['baz']
...     class __metaclass__(type):
...         def bar(self):
...             print 'slow initialization'
...             return 'apple'
...         bar = LazyAttribute(bar)
...     def __init__(self, baz):
...         self.baz = baz
...
py> f = Foo(1)
py> f.baz
1
py> f.bar
Traceback (most recent call last):
   File "<interactive input>", line 1, in ?
AttributeError: 'Foo' object has no attribute 'bar'
py> f.__class__.bar
slow initialization
'apple'
py> Foo.bar
'apple'

Note that if you want to reference the class variable, you have to 
specficially go through the class, instead of counting on the instance 
lookup as classes without __slots__ can.  But as long as you don't 
declare 'bar' as a slot, you should still be able to access Foo.bar.

Note that you probably don't want to have 'bar' as both a class variable 
and an instance variable -- then the instance variable will just hide 
the class variable...

HTH,

Steve



More information about the Python-list mailing list