Python Forum
How to access class variable? instances vs class
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How to access class variable? instances vs class
#1
Hello everyone, I am learning OOP in python, specifically class variables. It is clear to me what they are, but I do not get why they should be accessed through the instance. Referring to the following tutorial in the method apply_raise the variable can be accessed through the instance (line 15 --> self.pay = int( self.pay * self.raise_amount )). I tried to access the variable through the class (line 16 --> self.pay = int( self.pay * Employee.raise_amount ), and it works in the same way, at least it looks so to me. Is there any difference?

class Employee:

    raise_amount = 1.04

    def __init__(self ,first ,last ,pay ):
        self.first = first
        self.last = last
        self.pay = pay
        self.email = first+"."+last+"@company.com"

    def fullname(self):
        return "{} {}".format(self.first, self.last)

    def apply_raise(self):
        self.pay = int( self.pay * self.raise_amount )
       #self.pay = int( self.pay * Employee.raise_amount )
        return self.pay 
Reply
#2
At first sight, there is no difference: if it doesn't find the raise_amount member in the instance, Python will look for the member in the class, then in the ancester classes if any.

The self.raise_amount is the most robust syntax if you decide to change the structure of the classes later. For example if you change the name of the Employee class, you won't need to change self.raise_amount. Things get even better when you start defining subclasses, for example
class SpecialEmployee(Employee):
    raise_amount = 1.10

jane = SpecialEmployee('Jane', 'Doe', 5000)
jane.apply_raise()
Then Jane's new pay will be 5500 because self.raise_amount will use Jane's class instead of the Employee class.
Reply
#3
Thanks for the answer, I got the point about changing the class' name. I tested your subclass and it works in both ways though (self.raise_amount and Employee.raise_amount)...am I doing something wrong? Huh
Reply
#4
drSlump Wrote:it works in both ways though

Can you post the whole code? It should not give the same pay.
Reply
#5
Sorry it was my mistake. Everything works fine and I think I got the point. Here is the code:

class Employee:

    raise_amount = 2

    def __init__(self ,first ,last ,pay ):
        self.first = first
        self.last = last
        self.pay = pay
        self.email = first+"."+last+"@company.com"

    def fullname(self):
        return "{} {}".format(self.first, self.last)

    def apply_raise(self):
        # self.pay = int( self.pay * self.raise_amount )
        self.pay = int( self.pay * Employee.raise_amount)
        return self.pay

class SpecialEmployee(Employee):
    raise_amount = 10
So if I use self.raise_amount in the method apply_raise of the ancestor class Employee, the raise_amount class variable is always bound to the instance. Hence, if I change its value either in a child class (e.g. SpecialEmployee) or in any instance of the ancestor/child class, this value will be used. If I use Employee.raise_amount the class variable can be changed only through the class, thus Employee.raise_amount == value and will stay that value. I think I can say in a way that, using self.raise_amount the class variable is always accessible by the current instance of the class, right?

What confused me is that even defining Employee.raise_amount == value, I can still do:

emp_1 = Employee("John", "Doe", 5000)
emp_1.raise_amount = 1.1
print('raise_amount emp_1= ',emp_1.raise_amount)
print(emp_1.apply_raise())
print(emp_1.__dict__)
that provides as output:
Output:
raise_amount emp_1= 1.1 10000 {'first': 'John', 'last': 'Doe', 'pay': 10000, 'email': '[email protected]', 'raise_amount': 1.1}
so it seemed to me that the variable class raise_amount was changed, but it was not, actually the method apply_raise provides the correct result. But why is the 'raise_amount': 1.1 listed in emp_1.__dict__ then?
Reply
#6
You cannot change the class attribute through the assignment
emp_1.raise_amount = 1.1
This creates (or updates) an instance attribute without changing the class attribute. This is because instance attributes don't need to be declared in python. Assigning emp_1.spam = value creates the spam instance attribute, regardless of what the class contains.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  class and runtime akbarza 4 277 Mar-16-2024, 01:32 PM
Last Post: deanhystad
  Operation result class SirDonkey 6 421 Feb-25-2024, 10:53 AM
Last Post: Gribouillis
  The function of double underscore back and front in a class function name? Pedroski55 9 561 Feb-19-2024, 03:51 PM
Last Post: deanhystad
  super() and order of running method in class inheritance akbarza 7 594 Feb-04-2024, 09:35 AM
Last Post: Gribouillis
  Class test : good way to split methods into several files paul18fr 4 402 Jan-30-2024, 11:46 AM
Last Post: Pedroski55
  Good class design - with a Snake game as an example bear 1 1,713 Jan-24-2024, 08:36 AM
Last Post: annakenna
  question about __repr__ in a class akbarza 4 527 Jan-12-2024, 11:22 AM
Last Post: DeaD_EyE
  error in class: TypeError: 'str' object is not callable akbarza 2 444 Dec-30-2023, 04:35 PM
Last Post: deanhystad
  super() in class akbarza 1 401 Dec-19-2023, 12:55 PM
Last Post: menator01
  error occuring in definition a class akbarza 3 636 Nov-26-2023, 09:28 AM
Last Post: Yoriz

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020