Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Access Class method and variable using self

In below example Test class has two instance method and one classmethod

In set_cls_var_1 method I set class variable using self.

In set_cls_var_2 method I call class method using self.

   class Test():

        #class variable
        cls_var = 10

        def __init__(self):
           obj_var=20

        def set_cls_var_1(self,val):
            #second method to access class variable
            print "first "
            self.cls_var = val

        def set_cls_var_2(self):
            print "second"
            self.task(200)

        @classmethod
        def task(cls,val):
            cls.cls_var = val


t=Test()

#set class variable by first method
t.set_cls_var_1(100)

print Test.cls_var

#set class variable by second method
t.set_cls_var_2()

print Test.cls_var

Output

first 
10
second
200

Expected Output

first 
100
second
200

My question is: why only classmethod can call by self, Why not class variable

like image 378
Kallz Avatar asked Jul 15 '17 18:07

Kallz


3 Answers

When you attempt to access an object's attribute using self, Python first searches the object's attributes. If it cannot find it there, then is searches the object's class's attributes. That is what's happening in your case;

Python first searches t's attributes. It doesn't find cls_var, so it then searches the T class's attributes. It finds cls_var so it stops, and returns cls_var's value.

However, when assigning attributes to self, Python always assigns them directly to the object, and never the object's class unless explicitly told to do so. That's why assinging self.cls_var to 100 didn't affect Test's cls_var attrbiute.

like image 126
Christian Dean Avatar answered Oct 16 '22 11:10

Christian Dean


I find something else that always use following way to access classmethod or variable in instance method

class Test():
    #class variable
    cls_var = 10

    def __init__(self):
        obj_var=20

    def set_cls_var_1(self,val):
        #first method to access class variable
        print "first type"
        cls = self.__class__
        cls.cls_var = val



t=Test()
#set class variable by first method

t.set_cls_var_1(100)

print Test.cls_var
like image 7
Kallz Avatar answered Oct 16 '22 10:10

Kallz


When defining the Test class like you did, python creates a class object called Test which has an attribute cls_var equal to 10. When you instantiate this class, the created object doesn't have cls_var attribute. When calling self.cls_var it is actually the class' attribute that is retrieved due to the way python resolves attributes.

However when set self.cls_var the value is set at the object level! So further call to self.cls_var will give you the value of the object's attribute, and not the class' anymore!

Maybe this bit of code will make this clearer:

class A(object):
    a = 1
a = A()
print a.a  # prints 1
A.a = 2
print a.a  # prints 2

You see that even though when set the value at the class level, the changes are repercuted on the object, because, python will look up for the attribute in the class when it is not found at the object level.

When calling Test.cls_var it is the cls_var attribute of the class you are accessing! Not the one of the object you just modified.

like image 1
Anis Avatar answered Oct 16 '22 11:10

Anis