Eduardo
Eduardo

Reputation: 701

Class method calling twice

I have the following code.

class DobleTSim():
    def __init__(self, bf, hw, tf, tw):
        self.bf = bf
        self.hw = hw  
        self.tf = tf
        self.tw = tw

    def m_in_maj(self):
        print('foo')
        return 2 * (self.bf * self.tf * (self.tf / 2 + self.hw / 2))


    def m_est_maj(self):
        return self.m_in_maj() / ((self.hw + 2 * self.tf) / 2)

A = DobleTSim(200, 500, 12, 12)

print(A.m_in_maj(), A.m_est_maj())

When I execute the code, the output is :

foo
foo
1228800.0 4690.076335877862

How can I avoid execute the method "m_in_maj" twice?

-----EDIT-----

Another solution can be the use of a property and the lru_cache decorator. Is there a disadvantage when using this?.

import functools

class DobleTSim():
    def __init__(self, bf, hw, tf, tw):
        self.bf = bf
        self.hw = hw  
        self.tf = tf
        self.tw = tw

    @property
    @functools.lru_cache()
    def m_in_maj(self):
        print('foo')
        self.a = 2 * (self.bf * self.tf * (self.tf / 2 + self.hw / 2))
        return self.a

    def m_est_maj(self):
        return self.m_in_maj / ((self.hw + 2 * self.tf) / 2)

Upvotes: 0

Views: 2576

Answers (2)

erik258
erik258

Reputation: 16305

You call it twice. Once in the print() at the end, once within the call to m_est_maj.

6 math operations is quite a cheap operation. You probably won't get a meaningful performance increase by caching the result. But you could do so, if you wanted to. You could call m_in_maj from __init__ and save the result to an instance attribute, and refer to that instead of the function call.

Or you could have the function check to see if the instance attribute was already defined, compute on the first call, and return on subsequent calls.

This is a pretty common general approach I see around:

class DobleTSim():
    def __init__(self, bf, hw, tf, tw):
        self.bf = bf
        self.hw = hw
        self.tf = tf
        self.tw = tw

    def m_in_maj(self):
        if not hasattr( self, '_m_in_maj_result'):
            print('foo')
            self._m_in_maj_result =  \
                2 * (self.bf * self.tf * (self.tf / 2 + self.hw / 2))
        return self._m_in_maj_result


    def m_est_maj(self):
        return self.m_in_maj() / ((self.hw + 2 * self.tf) / 2)

A = DobleTSim(200, 500, 12, 12)

print(A.m_in_maj(), A.m_est_maj())

Based on How to know if an object has an attribute in Python, it might be more pythonic to do something like this:

def m_in_maj(self):
    try:
        return self._m_in_maj_result
    except AttributeError:
        print('foo')
        self._m_in_maj_result =  \
            2 * (self.bf * self.tf * (self.tf / 2 + self.hw / 2))
        return self._m_in_maj_result

Upvotes: 3

Right leg
Right leg

Reputation: 16720

Your m_in_maj method is called in the m_est_maj method:

def m_est_maj(self):
    return self.m_in_maj() / ((self.hw + 2 * self.tf) / 2)

Instead, give it an optional argument, and call m_in_maj only if this argument is not passed:

def m_est_maj(self, x=None):
    if x is None:
        x = self.m_in_maj()
    return x / ((self.hw + 2 * self.tf) / 2)

Then, when calling m_est_maj:

x = A.m_in_maj()
print(x, A.m_est_maj(x))

Upvotes: 0

Related Questions