Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the proper pattern in Python for implementing lazy getters?

Sometimes I like to write getter attributes for an object such that the first time they are called, the heavy lifting is done once, and that value is saved and returned on future calls. In objective-c I would use an ivar or a static variable to hold this value. Something like:

- (id)foo
{
    if ( _foo == nil )
    {
        _foo = // hard work to figure out foo
    }
    return _foo
}

Does this same pattern hold up well in Python, or is there a more accepted way of doing this? I have basically the same thing so far. What I don't like about my solution is that my object gets cluttered up with values and getters for those values:

def foo(self):
    if not hasattr(self, "mFoo":
        self.mFoo = # heavy lifting to compute foo
    return self.mFoo
like image 214
D.C. Avatar asked Mar 12 '12 05:03

D.C.


2 Answers

Use a lazy property instead. Getters are so 1990's.

like image 79
Ignacio Vazquez-Abrams Avatar answered Nov 03 '22 01:11

Ignacio Vazquez-Abrams


Instead of doing an explicit "hasattr" test every time, let the Python runtime do that for you. Define __getattr__ in your class, which is only called when an undefined attribute is referenced.

class Sth(object):
    @property
    def a(self):
        print "property a"
        return self._a

    def _a_compute(self):
        # put expensive computation code here
        print "_a_compute"
        return 1000

    def __getattr__(self, attr):
        print "__getattr__"
        if attr == '_a':
            self._a = self._a_compute()
            return self._a


ss = Sth()
print "first time"
print ss.a
print
print "second time"
print ss.a

Prints the following:

first time
property a
__getattr__
_a_compute
1000

second time
property a
1000

You could leave out the property and have __getattr__ test for 'a' directly, but then you wouldn't have the visibility to 'a' as an attribute in dir for things like introspection or IDE autocomplete.

like image 24
PaulMcG Avatar answered Nov 03 '22 01:11

PaulMcG