0

I have multiple functions that make use of a single variable, the computation of this variable is costly, and so I would not like to repeat this. I have two simple proposed methods for doing this, and was wondering which you feel is more "pythonic" or a better method.

class A:

    def __init__(self):
        self.hasAttr = False

    def compute_attr(self):
        self.attr = 10
        self.hasAttr = True #for func2 only

    def func1(self):
        try:
            print self.attr == 10
        except AttributeError:
            self.compute_attr()
            self.func1()

    def func2(self):
        if not self.hasAttr: self.compute_attr()
        print self.attr == 10

a = A()
a.func1()
a.func2()

func1 uses a simple try except to catch the AttributeError and compute the attribute in this case. func2 uses a stored boolean to check if the computation has been completed or not.

Is there any reason as to one method would be preferred over another? Furthermore, would there be any point in defining a decorator that does the check as in func2?

Thanks for any help.

Oli
  • 167
  • 8

1 Answers1

2

Basically your question is "should I use EAFP or should I use LBYL". The answer is : it depends. A try/except block is almost free to setup but very costly when used (when an exception is actually raised) while a test has a constant (and rather cheap for this kind of tests) cost, so if you most often don't have the attribute set you may prefer the LBYL solution, while if you're confident it will already have been set most of the time then EAFP may be a better choice.

Note also there are simpler (and more reliable) ways to test weither your attribute has been computed - either by setting it in the initializer with a sentinel value - None is an obvious candidate unless it also happens to be a valid value - or by using hasattr(obj, attrname). You can also use a property to encapsulate the access, ie:

class EAFB(object):

    @property
    def attr(self):
        try:
            return self._attr
        except AttributeError:
            self._attr = costly_computation()
            return self._attr


   def func(self):
       print "attr is %s" % self.attr



class LBYL(object):

    @property
    def attr(self):
        if not hasattr(self, "_attr"):
            self._attr = costly_computation()
        return self._attr


   def func(self):
       print "attr is %s" % self.attr
Community
  • 1
  • 1
bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118
  • Hadn't come across the _property_ function in python yet, nor the EAFP or LBYL paradigms. Using property as a decorator is the way I will go (with the EAFP method, things should normally already be initialised). Thank you for answering the question of which method to use. I now see how this question may be a duplicate, however this answer is much clearer than responses I've seen in other similar questions. Thanks – Oli Mar 14 '17 at 16:45