pietà pietà - 1 month ago 9
Python Question

how to change the value of a global varible in the child classe of python?

I have a problem in declaring variable in the child class. I have simplified the case because the code is too long and have many dependencies. So here is the case :

I have 2 classes

A
and
B
:

class A ():
global_var=0
def some_function(self):
return self.global_var+2

class B(A):

def method_that_returns_global_var(self):
#do some operations on global_var
global_var=(.....some logic....)
return global_var


How to declare the
global_var
in the child class
B
so that it executes the function of the parent class
some_function
with the value of global_var of child class
B

Answer

So... There's a couple of concepts that you should probably clarify.

That global_var is not a global variable. It's a class attribute. It means it's only defined once: When you declare the class. After that, all the classes of the same type (or their inherited classes) will share the same variable. I found this, which is probably helpful.

That means that all the instances of type A or of any type inheriting from A (namely B in the example) that you create will share it. However, you still need to access them through self or through the cls (usually the class instance is named like that in classmethods) What you're doing in this method...

def method_that_returns_global_var(self):
   #do some operations on global_var
   global_var=(.....some logic....)

... is just creating a global_var variable local to the method_that_returns_global_var method (and has nothing to do with the global_var in the class)

If it helps you see it (it certainly helps me), you can think of that global_var as attached to the class, not to the instances of that class.

This means that class B already has access to global_var because it inherits from A. When you try to access global_var in an instance method (the ones that you pass self to, broadly speaking), what the interpreter is gonna try to do is find the global_var attribute among the ones of the instance (self). If it doesn't find it it will go to the class. However (very important) when you assign in an instance method (you do self.global_var = whatever), the interpreter will just place global_var in the instance (in its "internal" dictionary of attributes __dict__) Don't let that confuse you!

See this:

class A(object):
    global_var = 5

    def some_function(self):
        return self.global_var + 2

    def print_global_bar(self):
        print("Global bar value=%s" % self.global_var)


class B(A):
    def method_that_returns_global_var(self):
        # do some operations on global_var
        self.global_var = 1000
        return self.global_var


if __name__ == "__main__":
    b = B()
    b.print_global_bar()
    b.method_that_returns_global_var()
    b.print_global_bar()
    print("Because `method_that_returns_global_var` does an ASSIGNMENT, now I have two `global_var`."
          " One in the class, one in the instance `b`")
    print("In the instance: %s" % b.global_var)
    print("In  the class: %s" % b.__class__.global_var)

It outputs:

Global bar value=5
Global bar value=1000
Because `method_that_returns_global_var` does an ASSIGNMENT, now I have two `global_var`. One in the class, one in the instance `b`
In the instance: 1000
In  the class: 5

If you wanted to do the assignment to the class variable in method_that_returns_global_var you should either do it a class method (with the @classmethod decorator) or access the class of the instance (located in self.__class__)

See now:

class A(object):
    global_var = 5

    def some_function(self):
        return self.global_var + 2

    def print_global_bar(self):
        print("Global bar value=%s" % self.global_var)


class B(A):
    def method_that_returns_global_var(self):
        # do some operations on global_var
        self.__class__.global_var = 1000
        return self.global_var


if __name__ == "__main__":
    b = B()
    b.print_global_bar()
    b.method_that_returns_global_var()
    b.print_global_bar()
    print("In the instance: %s" % b.global_var)
    print("In  the class: %s" % b.__class__.global_var)

Outputs:

Global bar value=5
Global bar value=1000
In the instance: 1000
In  the class: 1000

See the difference? In the first method, doing self.global_var = 1000 creates a new attribute in the instance, disregarding whatever is written in the class. Basically, you have two global_vars around: One connected to the class (whose value is still 5), and one connected to the instance (whose value is 1000). In the second method, you are accessing and modifying all the time the class variable (A.global_var)

I recommend you play a bit more with this... More prints, more .__class__... things like that. :-)