The size attribute only needs to be computed once and stays constant after that. The lazy property recipe of Scott David Daniels looks promising. I'll try that, when I've installed Python 2.4. However, I need my package to work on machines where there is Python 2.2 and 2.3 only.
Note that:
@deco
def func(...):
...
is basically just syntactic sugar for:
def func(...):
...
func = deco(func)
So you don't need 2.4 to use the recipe; you just need a version of Python that supports descriptors (2.2 or later) since the recipe uses a class with __get__. I believe the following code should work for Python 2.2 and later, though I only have 2.4 to test it on at home.
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 B(object): ... def __init__(self, length): ... self._length = length ... def size(self): ... print 'some expensive calculation' ... return self._length ... size = LazyAttribute(size) ... py> class D(B): ... def __init__(self, length): ... super(D, self).__init__(length) ... self.value = 1 ... py> b = B(5) py> b.size some expensive calculation 5 py> b.size 5 py> d = D(6) py> d.size some expensive calculation 6 py> d.size 6
Note that b.size and d.size are only calculated once each, and if d.size is never accessed, you'll never incur the costs of calculating it.
Steve -- http://mail.python.org/mailman/listinfo/python-list