-2

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

pietà
  • 760
  • 1
  • 11
  • 37
  • 1
    PS : please when down voting , explain to us as newbies why :'( or at least say that it's impossible or python don't permit that !! – pietà Nov 01 '16 at 16:52

3 Answers3

3

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. :-)

Community
  • 1
  • 1
Savir
  • 17,568
  • 15
  • 82
  • 136
  • 1
    You're welcome. I know it can get a bit tricky **:-)** (and wait until you start learning that a `class` is also an instance of type `type`, haha)... Weeeell... that can be for some other occasion,**;-)**. Have fun coding! – Savir Nov 01 '16 at 18:38
1

Despite the "global" in the name, variable is actually a class field. You can overwrite it in child class like this (I shortened it to "var"):

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

 class B(A):
     var = 1


 B().some_function()  # =3
Eugene Prikazchikov
  • 1,794
  • 1
  • 13
  • 11
1

When you define a variable in the class scope it becomes a class variable. You can refer to it using class name.

class A():
    var = 123

print(A.var)
>>> 123

This variable will get inherited, so you should be able to do this

class B(A):
    pass

print(B.var)
>>> 123

and you should be able to override the default in the child class or change its value in the methods

class C(A):
    var = 234

    def inc_var(self):
        self.var += 1

print(C.var)
>>> 234
c = C()
c.inc_var()
print(C.var)
>>> 235
Mad Wombat
  • 14,490
  • 14
  • 73
  • 109