Python lazy non-data descriptor
# -*- coding: utf-8 -*- | |
# Copyright (c) 2015 Matthew Zipay <mattz@ninthtest.net>. All rights reserved. | |
# Licensed under the MIT License <http://opensource.org/licenses/MIT>. | |
class lazy: | |
r"""Decorate a no-arg getter to have lazy initialization behavior. | |
The first time the property is accessed on an instance, the computed | |
value is stored in the instance ``__dict__`` (using the same name as | |
the getter). Subsequent access returns the already-computed value as | |
a simple instance attribute. | |
This works because an attribute in an instance ``__dict__`` takes | |
precendence over a same-named, non-data descriptor in a class | |
``__dict__``. | |
>>> class Example: | |
... @lazy | |
... def expensive(self): | |
... print("initializing...") | |
... return "the computed value" | |
... | |
>>> x = Example() | |
>>> x.expensive | |
initializing... | |
'the computed value' | |
>>> x.expensive | |
'the computed value' | |
""" | |
def __init__(self, fget): | |
""" | |
:param fget: a no-arg method that computes and returns a value | |
""" | |
self._fget = fget | |
def __get__(self, obj, obj_type=None): | |
"""Return the computed value after setting it as an instance | |
attribute with the same name as the descriptor. | |
:param obj: an instance of the class that owns the getter | |
:keyword obj_type: the class of *obj* | |
:return: the value computed and returned by the getter | |
""" | |
if (obj is not None): | |
value = self._fget(obj) | |
setattr(obj, self._fget.__name__, value) | |
return value | |
# just return the descriptor itself if there's no instance | |
return self |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment