Hello, 2017-06-04 Nathaniel Smith <njs@pobox.com> dixit:
class LazyConstants: def __getattr__(self, name): value = compute_value_for(name) setattr(self, name, value) return value
__getattr__ is only called as a fallback, so by setting the computed value on the object we make any future attribute lookups just as cheap as they would be otherwise.
Another solution is to use a Pyramid's-@reify-like decorator to make a caching non-data descriptor (i.e., the kind of descriptor that can be shadowed with an ordinary instance attribute): ``` class LazyConstants: @reify def FOO(self): return <complicated computation...> @reify def BAR(self): return <another complicated computation...> ``` In my work we use just @pyramid.decorator.reify [1], but the mechanism is so simple that it you can always implement it by yourself [2], though providing some features related to_ _doc__/introspection-ability etc. may need some additional deliberation to do it right... That may mean to it would be worth to add it to the standard library. Wouldn't be? Cheers. *j [1] See: http://docs.pylonsproject.org/projects/pyramid/en/latest/api/decorator.html#... [2] The gist of the implementation is just: ``` class lazyproperty(object): def __init__(self, maker): self.maker = maker def __get__(self, instance, owner): if instance is None: return self value = self.maker(instance) setattr(instance, self.maker.__name__, value) return value ```