On 4 June 2017 at 17:37, Nathaniel Smith <n...@pobox.com> wrote: > I think in general I'd recommend making the API for accessing these > things be a function call interface, so that it's obvious to the > caller that some expensive computation might be going on. But if > you're stuck with an attribute-lookup based interface, then you can > use a __getattr__ hook to compute them the first time they're > accessed: > > 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. > > You can get this behavior onto a module object by doing > "sys.modules[__name__] = Constants()" inside the module body, or by > using a <del>hack</del> elegant bit of code like > https://github.com/njsmith/metamodule/ (mostly the latter would only > be preferred if you have a bunch of other attributes exported from > this same module and trying to move all of them onto the LazyConstants > object would be difficult).
This reminds me: we could really use some documentation help in relation to https://bugs.python.org/issue22986 making module __class__ attributes mutable in Python 3.5+ At the moment, that is just reported in Misc/NEWS as "Issue #22986: Allow changing an object's __class__ between a dynamic type and static type in some cases.", which doesn't do anything to convey the significant *implications* of now being able to define module level properties as follows: >>> x = 10 >>> x 10 >>> import __main__ as main >>> main.x 10 >>> from types import ModuleType >>> class SpecialMod(ModuleType): ... @property ... def x(self): ... return 42 ... >>> main.__class__ = SpecialMod >>> x 10 >>> main.x 42 (I know that's what metamodule does under the hood, but if the 3.5+ only limitation is acceptable, then it's likely to be clearer to just do this inline rather than hiding it behind a 3rd party API) One potentially good option would be a HOWTO guide on "Lazy attribute initialization" in https://docs.python.org/3/howto/index.html that walked through from the basics of using read-only properties with double-underscore prefixed result caching, through helper functions & methods decorated with lru_cache, and all the way up to using __class__ assignment to enable the definition of module level properties. Cheers, Nick. -- Nick Coghlan | ncogh...@gmail.com | Brisbane, Australia _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/