Following technique described in a previous post, another interesting problem can be solved.
I would like to delay object method evaluation until I access the method and I want to evaluate it only once.
In straight-forward approach, the following can be written:
class BigMath(object):
def get_big_data(self):
if hasattr(self, "_rv"):
return self._rv
self._rv = self._get_big_data()
return self._rv
def _get_big_data(self):
print "working hard...."
return 42
>>> m = d.BigMath() >>> m.get_big_data() working hard.... 42 >>> m.get_big_data() 42 >>>Hard work is only done once as we can see. Additionally we can rename a
get_big_data to big_data and make is property.
The above approach is simple and trivial. However reduplicating it from class to class and from method to method makes things boggy. I would like to have something reusable that I can apply on desired methods. Like this:
class BigMath(object):
@OneTime
def big_data(self):
print "working hard...."
return 42
Much more elegant, right? Now lets reveal that magic OneTime decorator.
class OneTime(object):
def __init__(self, func):
self.func = func
def __get__(self, obj, cls):
to_augment = obj or cls
rv = self.func(to_augment)
setattr(to_augment, self.func.__name__, rv)
return rv
Its actually straight-forward if you are familiar with class-as-decorator technique:
- Again, we create class that behaves both as decorator and descriptor
- This is parameter-less decorator, so we need to implement only
__init__and not__call__ - We records the method function
- When method is accessed (i.e.
__get__gets invoked), we execute the function and cache its results by overriding ourselves.
No comments:
Post a Comment