What is the correct model in Python for implementing lazy getters?

Sometimes I like to write getter attributes for an object, so the first call is heavy lifting once, and this value is saved and returned on subsequent calls. In objective-c, I would use ivar or a static variable to store this value. Sort of:

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

Does the same template work well in Python, or is there a more acceptable way to do this? So far I have basically the same thing. What I don't like about my solution is that my object is clogged with values ​​and getters for these values:

 def foo(self): if not hasattr(self, "mFoo": self.mFoo = # heavy lifting to compute foo return self.mFoo 
+6
source share
4 answers

Use a lazy property . Getters in the 1990s .

+7
source

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

 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 can leave this property and have __getattr__ test for 'a' directly, but then you will not have the visibility "a" as an attribute in dir for things like introspection or autocomplete IDE.

+3
source

You can use the exact same template in Python. You seem to be worried about whether my_object.get_foo() needs to be done all the time in Pythonic. Fortunately, Python gives you a good tool to work here in the form of properties :

 class my_class(object): @property def foo(self): # calculate if needed return self._foo 

This allows you to use something that is used as an attribute, even if it is implemented as a function. those. users will do my_object.foo , and do not care that it performs the function behind the scenes.

Another thing is that the Python convention says that private attributes are written by _foo , not mFoo .

+1
source

I would do something like this:

 @property def foo(self): return self._foo_value if hasattr(self, '_foo_value') else calculate_foo() def calculate_foo(self): self._foo_value = # heavy foo calculation return self._foo_value 

Now you can access "foo" if it has already been calculated or not, using:

 object.foo 
+1
source

Source: https://habr.com/ru/post/910471/


All Articles