Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

pythonic class instance attribute calculated from other attributes

I have a class instance with attributes that are calculated from other attributes. The attributes will change throughout the life of the instance. All attributes are not necessarily defined when the object is initialized.

what is the pythonic way to calculate attributes from other attributes?

This is a simple example, the calculations have numerous input variables ("a" below) and calculations ("b" & "c").

a = something
b = function of a (a+5)
c = function of a and b (a*b)

I've tried numerous implementations. Here is a decent one to communicate my intention.

 class CalcAttr(object):

    def __init__(self):
        self._a = None
        self._b = None
        self._c = None

    @property
    def a(self):
        return self._a
    @a.setter
    def a(self,value):
        self._a = value

    @property
    def b(self):
        self.calc_b()
        return self._b

    @property
    def c(self):
        self.calc_c()
        return self._c


    def calc_b(self):
        self._b = self._a + 5

    def calc_c(self):
        self._c = self._a * self._b

def test():
    abc = CalcAttr()
    a = 5
    return abc.c

Note: t.c works if I first call t.b first.

> >>> t=abc.test()
> >>> t.c Traceback (most recent call last):   File "<stdin>", line 1, in <module>   File "abc.py", line 22, in c
>     self.calc_c()   File "abc.py", line 29, in calc_c
>     self._c = int(self._a) * int(self._b) TypeError: int() argument must be a string or a number, not 'NoneType'
> >>> t.b 10
> >>> t.c 50
> >>>

Keep in mind most of the real calculations are dependent on multiple attribures (5-10 input variables & as many calculated ones).

My next iteration will include a "calculate_model" function that will populate all calculated attributes after checking that all inputs are defined. Maybe that will be the pyhonic answer?

Thanks!

Update - working solution

I created a method that calculates each attribute in order:

def calc_model(self):
    self.calc_b()
    self.calc_c()

Each calculated attribute calls that method

@property
def c(self):
    self.calc_model()
    return self._c

I'm not sure if this is proper, but it works as desired...

like image 914
twinturbotom Avatar asked Nov 30 '15 03:11

twinturbotom


People also ask

What is the difference between class attributes and instance of attributes?

Class attributes are the variables defined directly in the class that are shared by all objects of the class. Instance attributes are attributes or properties attached to an instance of a class.

What are the attributes that have same value for all class instance?

Class attributes are attributes which are owned by the class itself. They will be shared by all the instances of the class. Therefore they have the same value for every instance.

What are the two ways to access instance attributes?

There are two ways to access the instance variable of class: Within the class in instance method by using the object reference ( self ) Using getattr() method.

Are instances the same as attributes?

We make a distinction between instance attributes and class attributes. Instance Attributes are unique to each object, (an instance is another name for an object).


1 Answers

If I understand your question correctly, you should compute b and c in their getters. You should also probably require that the user passes a value for a in the initializer, since b and c can't be computed without a. Also, it doesn't seem like there is much of a reason to keep _a, _b, and _c around -- unless b and c are expensive to compute and you'd like to cache them.

For example:

class CalcAttr(object):

    def __init__(self, a):
        self.a = a

    @property
    def b(self):
        return self.a + 5

    @property
    def c(self):
        return self.a * self.b

Such that

>>> x = CalcAttr(42)
>>> x.c
1974
like image 178
jme Avatar answered Sep 23 '22 03:09

jme