How to update a class attribute when an instance attribute changes?

95 views Asked by At

I am working on optimization problems. As you know, optimization is an iterative process. Some sections are selected, and the weight of all sections is calculated.

I have code like this:

class Test:
    W = 0

    def __init__(self, l, A):
        self.l = l
        self.A = A
        Test.W += self.A * self.l

instance1 = Test(5, 10)
instance2 = Test(3, 7)
instance3 = Test(6, 13)

print(Test.W)

instance1.A = 20
instance2.A = 30
instance3.A = 40

print(Test.W)

At creation of instances 1-3, the program calculated 149 for W. It is correct. But if I change A values, the result is 149 again and again.

How can I update the class attribute W when I change A or l?

2

There are 2 answers

0
blhsing On BEST ANSWER

If you want modifications made to an instance attribute to effect the value of a class attribute, you can make the instance attribute a property and place the additional logics in its setter method instead:

class Test:
    W = 0

    def __init__(self, l, A):
        self.l = l
        self.A = A

    @property
    def A(self):
        try:
            return self._A
        except AttributeError:
            return 0

    @A.setter
    def A(self, value):
        Test.W += (value - self.A) * self.l
        self._A = value

so that:

instance1 = Test(5, 10)
instance2 = Test(3, 7)
instance3 = Test(6, 13)

print(Test.W)

instance1.A = 20
instance2.A = 30
instance3.A = 40

print(Test.W)

outputs:

149
430

Demo: https://ideone.com/pqUN4w

0
Arush Rai On

The issue is related to the fact that the class attribute W is calculated only once during the instantiation of the class. If you want to update the class attribute W when you change the values of A or l for an instance, you can create a method to recalculate and update W. You can use a class method for this purpose.

    class Test:
    W = 0

    def __init__(self, l, A):
        self.l = l
        self.A = A
        Test.calculate_and_update_W(self)

    @classmethod
    def calculate_and_update_W(cls, instance):
        cls.W += instance.A * instance.l

# Create instances
instance1 = Test(5, 10)
instance2 = Test(3, 7)
instance3 = Test(6, 13)

# Print initial value of Test.W
print(Test.W)

# Update A values for instances
instance1.A = 20
instance2.A = 30
instance3.A = 40

# Recalculate and update Test.W
Test.calculate_and_update_W(instance1)
Test.calculate_and_update_W(instance2)
Test.calculate_and_update_W(instance3)

# Print updated value of Test.W
print(Test.W)

In this version, I added a calculate_and_update_W class method, which takes an instance of the class as an argument and recalculates and updates the class attribute W accordingly. This method is then called during the initialization (init) to set the initial value and can be called again whenever you want to update W based on the current values of A and l.