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 -- http://mail.python.org/mailman/listinfo/python-list