[Python-ideas] Defer Statement
Nick Coghlan
ncoghlan at gmail.com
Sun Jun 4 04:12:20 EDT 2017
On 4 June 2017 at 17:37, Nathaniel Smith <njs at 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 | ncoghlan at gmail.com | Brisbane, Australia
More information about the Python-ideas
mailing list