2

I have changed the value of class variable raise_amount for one instance. Later I have changed the value of the class variable with the classmethod set_raise_amt but it could not change the value for that particular instance, even though for the other instance it was changed. It's probably a noob question, but please help me understand.

class Employee:
    """
    A class that keeps employee records
    """
    raise_amount = 1.04

    def __init__(self, first, last):
        self.first = first
        self.last = last

    @classmethod
    def set_raise_amt(cls, amount):
        cls.raise_amount = amount


emp_1 = Employee("Test1", "Title1")
emp_2 = Employee("Test2", "Title2")

emp_1.raise_amount = 1.07
Employee.set_raise_amt(1.09)
Employee.raise_amount = 1.09

print(Employee.raise_amount)
print(emp_1.raise_amount)
print(emp_2.raise_amount)

The output is

1.09
1.07
1.09
[Finished in 0.084s]
  • Did you mean to use `emp_2.set_raise_amount`? Calling `Employee.set_raise_amount` is not tied to an instance? – NelsonGon Apr 11 '21 at 16:30
  • 2
    `emp_1.raise_amount = 1.07` creates an instance attribute for `emp_1`. You didn't define any such instance attribute for `emp_2`, so when you access `emp_2.raise_amount`, you get the corresponding class attribute. – Thierry Lathuille Apr 11 '21 at 16:32
  • Thank you to everyone for clearing it. – Sagarmay Biswas Apr 11 '21 at 16:35
  • The question was linked as a duplicate did not answer this question. Which seems to be "Why is assigning to `self.attr` different to `cls.attr`?" – Dunes Apr 11 '21 at 16:44
  • https://stackoverflow.com/questions/2923579/python-class-attribute appears to be a better duplicate – Dunes Apr 11 '21 at 16:47

3 Answers3

2

You are having a conflict between a class variable and an instance variable. When you call emp_1.raise_amount = 1.07, you are creating an instance variable with the same name as your class variable, and python always solves it this way:

If the same attribute name occurs in both an instance and in a class, then attribute lookup prioritizes the instance

so emp_1.raise_amount will always refer the instance variable over the class one.

HuLu ViCa
  • 5,077
  • 10
  • 43
  • 93
0

You did not "change it" for emp_1. You created the instance member. Therefore, when asking for emp_1.raise_amount, the instance member value is returned, whereas emp_2.raise_amount is the class member.

dedObed
  • 1,313
  • 1
  • 11
  • 19
-1

Use @staticmethod instead of @classmethod :

@staticmethod
def set_raise_amt(amount):
    Employee.raise_amount = amount
Xavier Brassoud
  • 697
  • 6
  • 14
  • 2
    As this explicitely modifies a class attribute, this should rather be a class method (which would then get the class as first argument), not a static method. It should rather be written as `@classmethod def set_raise_amt(cls, amount): cls.raise_amount = amount` – Thierry Lathuille Apr 11 '21 at 16:39
  • 1
    The problem is the call `emp_1.raise_amount=1.07`, which creates a new instance variable with the same name as the class variable, so it doesn't matter how you define the method, the result will be the same. – HuLu ViCa Apr 11 '21 at 17:10