user3256451
user3256451

Reputation: 475

How instance variable are related to class variable in python

class myclass(object):
    i=0
    def increase(self):
        self.i+=1
        print('increased value:', self.i)

if __name__=='__main__':
    m=myclass()
    m.increase()

Here is a class variable and self.i is instance variable , on executing i get o/P as 1.

But if comment class variable i I get an error

self.i+=1
AttributeError: 'myclass' object has no attribute 'i'

what is the relation between class variable i and instance variable self.i here.

Upvotes: 1

Views: 65

Answers (4)

Florian H
Florian H

Reputation: 3082

A class variable is a variable which can be changed by all instances of your class. You call it by [class_name].[variable_name]

For Example:

class myclass(object):
    i=0
    def increase(self):
        myclass.i+=1
        print('incresed value:',self.i)

if __name__=='__main__':
    m=myclass()
    k = myclass()

    k.increase()
    m.increase()
    m.increase()
    m.increase()
    m.increase()
    k.increase()

results in

incresed value: 1
incresed value: 2
incresed value: 3
incresed value: 4
incresed value: 5
incresed value: 6

An instance variable on the other hand (like you have it) can only be accessed by the instance which created it (with self.[variable_name]). To access a variable, the variable first needs to be instantiated. Like

a+=5

would create an error while

a = 0
a+= 5 

would not

In your example the instance variable is not specificly instantiated. But because of the class variable (i=0) python automatically instantiates the instance variable (i) with the value of the class variable. (because class and instance variable have the same name)

In other words:

When in your example the class variable i=0 is removed python does not know what value your instance variable self.i should have in the beginning.

Upvotes: 0

andreas-hofmann
andreas-hofmann

Reputation: 2518

What happens is that you are shadowing the class variable with a member variable.

See what happens when you instanciate another myclass-object and add a few printouts to your code:

class myclass(object):
    i=0
    def increase(self):
        myclass.i+=1
        print('incresed value:',self.i)

if __name__=='__main__':
    m=myclass()
    n=myclass()
    print("m.i=", m.i)
    print("n.i=", n.i)
    m.increase()
    print("m.i=", m.i)
    print("n.i=", n.i)

The output is now:

m.i= 0
n.i= 0
incresed value: 1
m.i= 1
n.i= 0

You see that you incremented the value of the i-member of m, but not of n. This is because self (like this in c++) always refers to the current object instance. If you update your code to the following, you are actually incrementing the class variable:

def increase(self):
    myclass.i+=1
    print('incresed value:',self.i)

And the output changes to the following:

m.i= 0
n.i= 0
incresed value: 1
m.i= 1
n.i= 1

Like Guillaume Jacquenot already stated in his answer, if you'd like to use member variables, it is advisable to initialize them in __init__(). In your case, the interpreter ist just using the class variable with the same name when it can't find a member variable, and in the same line initializing a member variable (with identical name i). If you comment out the class variable, you're trying to increment a variable which does not exist yet, hence the interpreter error.

Upvotes: 1

K. Kirsz
K. Kirsz

Reputation: 1420

The problem you are facing is the lack of definition of i object after you remove the class variable. The i=0 statement is the only definition. It is the same with any other variable, nothing special happens here:

i+=1

yields the same error if you put it in main or anywhere. In order to do the increment += you need to have the object declared first.

You can do:

class myclass(object):
def increase(self):
    self.i=0
    self.i+=1
    print('increased value:', self.i)

which makes no sense, but illustrates the issue, i think.

Upvotes: 0

Guillaume Jacquenot
Guillaume Jacquenot

Reputation: 11717

You use the following statements to declare a constant inside your class. i is not supposed to be modified later.

class myclass(object):
     i=0

You can access it with

 value = myclass().i

If you want a counter, you declare it in the constructor __init__, and increase it in a method

class myclass(object):
    def __init__(self): 
        self.counter = 0
    def increase(self): 
        self.counter += 1

Upvotes: 0

Related Questions