Deb
Deb

Reputation: 1098

How to define a new subclass that only changes the parent class?

I have the following simplified class structure

class A():
    def foo(self):
        self.bar()

    def bar(self):
        print("A bar")

class B(A):
    def bar(self):
        print("B bar")

class C(A):
    def bar(self):
        print("C bar")

Now I also have a modified version of A

class ModA():
    def foo(self):
        print("hi")
        self.bar()

I now also want a additional versions of B and C that have ModA as parent class instead of A.

class ModB(ModA):
    def bar(self):
        print("B bar")

class ModC(ModA):
    def bar(self):
        print("C bar")

How do I define ModB and ModC without duplicating their entire definition except for the first line that defines the parents?

Upvotes: 1

Views: 62

Answers (2)

wwii
wwii

Reputation: 23753

Based on your toy example here is one way to do it.

class FooBase:
    def foo(self):
        self.bar()
class FooMod:
    def foo(self):
        print("hi")
        self.bar()

class A(FooBase):
    def bar(self):
        print("A bar")

class B(FooBase):
    def bar(self):
        print("B bar")

class C(FooBase):
    def bar(self):
        print("C bar")

class ModA(FooMod,A):
    pass
class ModB(FooMod,B):
    pass
class ModC(FooMod,C):
    pass

class BadModA(A,FooMod):
    pass

for thing in [A,B,C,ModA,ModB,ModC,BadModA]:
    thing = thing()
    print(thing.foo())
    print('**********')

You have to be careful how you order the base classes notice BadModA doesn't work because it finds the foo method in FooBase before looking in FooMod. You can see that in their Method Resolution Order's

In [15]: ModA.__mro__
Out[15]: [__main__.ModA, __main__.FooMod, __main__.A, __main__.FooBase, object]

In [16]: BadModA.__mro__
Out[16]: (__main__.BadModA, __main__.A, __main__.FooBase, __main__.FooMod, object)

While this works it seems like you could get yourself in trouble. you always have to remember which order to use - maybe someone will comment.


Here is another way, it flattens the structure out a bit, five bases and you mix them up

class FooBase:
    def foo(self):
        self.bar()
class FooMod:
    def foo(self):
        print("hi")
        self.bar()

class Abar:
    def bar(self):
        print("A bar")
class Bbar:
    def bar(self):
        print("B bar")
class Cbar():
    def bar(self):
        print("C bar")

class A(FooBase,Abar):
    pass
class B(FooBase,Bbar):
    pass
class C(FooBase,Cbar):
    pass

class ModA(FooMod,Abar):
    pass
class ModB(FooMod,Bbar):
    pass
class ModC(FooMod,Cbar):
    pass

Upvotes: 1

Błotosmętek
Błotosmętek

Reputation: 12927

It is impossible to answer without knowing what your "slight changes" might be, but in general, look at multi-inheritance - class ModB(ModA, B): might be what you need.

class ModB(ModA, B):
    pass
>>> b = ModB()
>>> b.foo()
hi
B bar

Upvotes: 1

Related Questions