2

Im having trouble finding an efficient solution to a Python inheritance problem.

So there exists some code like the following:

class Foo( object ):
        def __init__():
                self.some_vars
        def foo_func():
                x = Bar()
        def foo_bar_func()
                x += 1

class Fighters( Foo ):
        def __init__():
                Foo.__init__()
        def func1():
                Foo.some_attribute
        def func2():
                Foo.someother_func()

class Bar():
        def bar_func():
                #some stuff here

The problem lies in that I need to override Bar.bar_func() but that is two levels deep. I solved it by doing the following:

class Foo( Foo ):
        def __init__():
                Foo.__init__()
        def foo_func():          #Overridden method
                x = myBar()   

class myFighters( Foo ):
        def __init__():
                Foo.__init__()
        def func1():
                Foo.some_attribute
        def func2():
                Foo.someother_func()

class myBar():
        def bar_func():      #the function that I actually need to change
                #my sweet code here

The only thing that is actually different is myBar.bar_func() but I had to do at least 2 things that I think is ugly.

One is that I had to create a class Foo that inherits from Foo. This seems like an odd thing to do and doesnt leave things very clear. I did this to save me from having to rename every reference in myFighters from Foo to myFoo.

The second is that I have to copy all of the code from Fighters into myFighters for the sole purpose of using an overridden function in Bar(). Fighters and myFighters are exactly the same, except that Fighters uses the Foo that calls Bar() and myFighters uses the Foo that calls myBar(). Does anyone have any suggestions to fix those two issues? Or should I just be thankful I found a solution and move on with my life...

AlENeuman
  • 33
  • 1
  • 4

2 Answers2

0

All methods defined on a class take the instance as the first argument. The convention is to call the instance self and refer to it as such:

class Foo(object):
    def __init__(self):
        self.x = 1

Second, if you don't need to overwrite a method of a parent class, simply leave it out:

class Fighters(Foo):
    # __init__ would be here, but I leave it out to inherit the method

    def func_1(self):
        ...

Finally, if you want to reference the parents behavior, use super():

class MyFighters(Fighters):
    def __init__(self):
         super(MyFighters, self).__init__()
         self.y = 2

See also this example and the official Python docs on classes.

Community
  • 1
  • 1
Razzi Abuissa
  • 3,337
  • 2
  • 28
  • 29
0

After some code cleanup to make a runnable example:

class Foo( object ):
        def __init__(self):
                print("foo init")
                self.foo_func()
        def foo_func(self):
                print("making bar")
                self.x = Bar()
        def foo_bar_func(self):
                self.x.bar_func()

class Fighters( Foo ):
        def __init__(self):
                print("fighters init")
                Foo.__init__(self)
        def func1(self):
                Foo.some_attribute
        def func2(self):
                Foo.someother_func()

class Bar(object):
        def __init__(self):
                print("bar init")
        def bar_func(self):
                #some stuff here
                print("bar bar_func")

Instantiate an original fighter:

f1 = Fighters()
f1.foo_bar_func()

and it calls the method from the original bar class:

fighters init
foo init
making bar
bar init
bar bar_func

Now we can subclass Fighters with MyFighters and Bar with MyBar. Override the foo_func of the Foo class is MyFighters with a constructor call to MyBar and it does what you want with no copying of methods:

class MyFighters(Fighters):
        def foo_func(self):
                print("making mybar")
                self.x = MyBar()

class MyBar(Bar):
        def bar_func(self):
                print("mybar bar_func")

When we create a new fighter:

f2 = MyFighters()
f2.foo_bar_func()

we see that it calls the method from the new bar class:

fighters init
foo init
making mybar
bar init
mybar bar_func

Clearly this only worked because the the method which created the Bar object was trivial to subclass and replace. In general this would not be the case since it would probably be done directly within init rather than calling a method to do it. So the design of the original classes is what allowed this example to run.

Neapolitan
  • 2,101
  • 9
  • 21