Can you please tell me what is a difference between calling Class_name.class_variable and self.class_variable inside method. Here is the example:
class Employee:
raise_amount = 1.04
def __init__(self, first, last, pay):
self.first = first
self.last = last
self.pay = pay
def apply_raise(self):
self.pay = int(self.pay * Employee.raise_amount)
So I used an Employee.raise_amount, but i can also write this method like that:
def apply_raise(self):
self.pay = int(self.pay * self.raise_amount)
I tested that with:
emp_1 = Employee('James', 'Amb', 10000)
emp_2 = Employee('Test', 'User', 20000)
print("Original value")
print("emp_1.raise_amount", emp_1.raise_amount)
print("emp_2.raise_amount", emp_2.raise_amount)
emp_1.raise_amount = 1.1
print("emp_1.raise_amount = 1.1")
print("emp_1.raise_amount", emp_1.raise_amount)
print("emp_2.raise_amount", emp_2.raise_amount)
Employee.raise_amount = 1.2
print("Employee.raise_amount = 1.2")
print("emp_1.raise_amount", emp_1.raise_amount)
print("emp_2.raise_amount", emp_2.raise_amount)
I run the program using Employee.raise_amount and then self.raise_amount. In both situation OUTPUT is the same:
Original value
emp_1.raise_amount 1.04
emp_2.raise_amount 1.04
emp_1.raise_amount = 1.1
emp_1.raise_amount 1.1
emp_2.raise_amount 1.04
Employee.raise_amount = 1.2
emp_1.raise_amount 1.1
emp_2.raise_amount 1.2
So what is a difference and when should I use Class_name.class_variable and self.class_variable
Python attribute reading, with self.attribute
works like this:
__get__
method is called (not the case, I will get back here later)__dict__
attribute, and sees if it contains attribute
, if so, its fetched__set__
method, such as a function or method)__dict__
<- you are here!__gettattr__
method on the class if it existsThis set of rules is actually rather natural when one is making use of the language. But you have to take care if at any point you are writting back to the attribute - if you do something like self.attribute = value
, then the attribute is set in the instance, not on the class, and if in other method you are retrieving it by doing ClassName.attribute
it will see the orignal value, set on the class, not the value set on self
, even if it is the same instance.
All things considered, the natural design of always using self.attribute
will work better for read-only class attributes. If you need a special value for a single instance, you can set a new value for that instance only, and everything keeps working. For an example using your case, let's say that for most employees, the raise_ammount is 1.04, but one of them is special cased to be 1.06, any method or even external code can set the new attribute on the instance, and methods reading the value from self.
will peek the updated number.
As for "descriptors" - they are special objects bound to the class that feature one of __get__
, __set__
or __delete__
methods, and override attribute access on the instance and class. They are the mechanism used by the @property
decorator, and by methods and classmethods themselves (so that the language can insert the self
parameter in method calls).
Oh, and all these steps are encoded in the language in object.__getattribute__
method (not the same as __getattr__
). Any class that overrides __getattribute__
can rewrite these rules at will (usually one will only tweak access to certain attributes, in order to create a proxy object, or something similar, not come out with a full hierarchical set of rules nearly as complex)