Yuval Atzmon
Yuval Atzmon

Reputation: 5945

Compositional inheritance in python

I am looking for advice on how to construct some project I gonna work on.

I got a base class, with some methods.

class Base(object):
  def method1(self):
    # some code
  def method2(self):
    # some code
  def method3(self):
    # some code
... and some other methods

For my project, I cannot modify the Base class, and I must inherent from it in order to apply my project requirements.

I have several requirement that might be enabled or not. Depending on a given configuration. I.e. I'd like to be able to override either method1(), method2(), method3() or any combination of them.

One alternative is to construct several inheriting classes.

class Child1(Base):
  def method1(self): 
    # some code

class Child2(Base):
  def method2(self): 
    # some code

class Child3(Base):
  def method3(self): 
    # some code

And then maybe use multiple inheritance to apply any composition of them. However this approach wouldn't scale well for covering all possible combinations.. (e.g. what happens if I will have Child4()? )

Another alternative is just having a single inheritance class and use if clauses to select whether to call the super method or apply the derived behavior.

class Child(Base):
  def method1(self): 
    if not self.override1:
      # call super
    else:
      # some code

  def method2(self): 
    if not self.override2:
      # call super
    else:
      # some code

  def method3(self): 
    if not self.override3:
      # call super
    else:
      # some code

I am more in favor on this alternative, however I feel there got to be a better OO approach for doing this.

Any thoughts or suggestions?

Thanks a lot

PS: I am constrained to python 2.7, and since I plan to share the code, I rather have a solution that is easy to understand by an average python programmer (and not only by advanced programmers).

Upvotes: 2

Views: 105

Answers (2)

aghast
aghast

Reputation: 15310

Keep in mind that class definitions are executed code. You could conditionally define or ignore a method in your child class:

class Child(Base):
    if something:
        def method1(self, etc):
            pass

Here's an example. Note that setting the condition has to happen before the class definition - this is not a dynamic parameter:

#!python3
import sys

special = False

if "--special" in sys.argv:
    special = True


class Base:
    def method1(self):
        print("Base method1")


    def method2(self):
        print("Base method2")

class Child(Base):
    def method3(self):
        print("Child method3")

    if special:
        def method1(self):
            print("Child method1")


ch = Child()
ch.method1()
ch.method2()
ch.method3()

Output is:

$ python test.py --special
Child method1
Base method2
Child method3

$ python test.py
Base method1
Base method2
Child method3

Upvotes: 1

wwii
wwii

Reputation: 23753

I like the first choice it seems manageable, no code duplication:

class A:
    def one(self):
        return 'one |'
    def two(self):
        return 'two |'
    def three(self):
        return 'three |'
    def four(self):
        return 'four |'

class B(A):
    def one(self):
        return 'one foo |'

class C(A):
    def two(self):
        return 'two foo |'

class D(A):
    def three(self):
        return 'three foo |'

class BC(B, C):
    pass
class CD(C, D):
    pass
class BD(B, D):
    pass

Now you have seven things to choose from. If needed you can easily tell what kind of thing it is at run-time:

>>> bc = BC()
>>> isinstance(bc, A)
True
>>> isinstance(bc, CD)
False
>>> isinstance(bc, BC)
True

And you'll probably find out you forgot something and it is easy to add:

#oops now I need this
class X(A):
    def four(self):
        pass
# and this $#%^!*
class B1(A):
    def one(self):
        return 'one bar |'

Upvotes: 2

Related Questions