How do I say "two classes up in the inheritance chain" in python?

D

Daniel Fetchinson

I have two classes that both inherit from two other classes which both
inherit from a single class. The two children have two almost
identical methods:

class grandparent( object ):
def meth( self ):
# do something

class parent1( grandparent ):
def meth( self ):
# do something p1
super( parent1, self ).meth( )

class parent2( grandparent ):
def meth( self ):
# do something p2
super( parent2, self ).meth( )

class child1( parent1 ):
def meth( self ):
# do something c
super( parent1, self ).meth( ) # I want to invoke meth on grandparent

class child2( parent2 ):
def meth( self ):
# do something c
super( parent2, self ).meth( ) # I want to invoke meth on grandparent

The meth methods in child1 and child2 are the same, except that in the
last super call, one is referring to parent1, the other is referring
to parent2. If they were exactly the same I could use a mixin where I
could define this method, and both child1 and child2 would inherit
from this mixin too. In this way I wouldn't have to code these methods
twice. But how do I write this mixin? It needs to refer to the
grandparent in such a way that it works in both child1 and child2 and
bypasses both parent1 and parent2. How would I do that?

Notes: (1) of course child1 and child2 have all sorts of methods which
are different, only meth is almost the same. (2) I can't modify the
grandfather class.

Cheers,
Daniel
 
B

Bruno Desthuilliers

Daniel Fetchinson a écrit :
I have two classes that both inherit from two other classes which both
inherit from a single class. The two children have two almost
identical methods:

class grandparent( object ):
def meth( self ):
# do something

class parent1( grandparent ):
def meth( self ):
# do something p1
super( parent1, self ).meth( )

class parent2( grandparent ):
def meth( self ):
# do something p2
super( parent2, self ).meth( )

class child1( parent1 ):
def meth( self ):
# do something c
super( parent1, self ).meth( ) # I want to invoke meth on grandparent

If so, it might be better to explicitly call grandparent.meth (passing
self as first argument). But this is an obvious design smell IMHO. What
you have is :

def meth(self):
do_something_more_or_less_specific
call_granparent

Looks like a candidate for a template method. Since you don't have hand
on Grandparent, the simplest would be to add an additional base class, ie:


class Abstract(Grandparent):
def do_something(self):
raise NotImplementedError

def meth(self):
self.do_something()
super(Abstract, self).meth()


class Parent1(Abstract):
def do_something(self):
# do something p1

class Parent2(Abstract):
def do_something(self):
# do something p2


Now you're problem is to factor out do_something() for Child1 and
Child2. The solution is quite simple : just define it outside the class
statements, and adds it afterward:

def do_something_children(self):
# code here

class Child1(Parent1):
# code here

Child1.do_something = do_something_children

class Child2(Parent2):
# code here

Child2.do_something = do_something_children


HTH
 
D

Daniel Fetchinson

I have two classes that both inherit from two other classes which both
If so, it might be better to explicitly call grandparent.meth (passing
self as first argument). But this is an obvious design smell IMHO. What
you have is :

def meth(self):
do_something_more_or_less_specific
call_granparent

Looks like a candidate for a template method. Since you don't have hand
on Grandparent, the simplest would be to add an additional base class, ie:


class Abstract(Grandparent):
def do_something(self):
raise NotImplementedError

def meth(self):
self.do_something()
super(Abstract, self).meth()


class Parent1(Abstract):
def do_something(self):
# do something p1

class Parent2(Abstract):
def do_something(self):
# do something p2


Now you're problem is to factor out do_something() for Child1 and
Child2. The solution is quite simple : just define it outside the class
statements, and adds it afterward:

def do_something_children(self):
# code here

class Child1(Parent1):
# code here

Child1.do_something = do_something_children

class Child2(Parent2):
# code here

Child2.do_something = do_something_children

Thanks, this was very helpful. Also, thanks Duncan, your simple
suggestion was helpful too to just call the grandparent directly
(without super).

Cheers,
Daniel
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,772
Messages
2,569,593
Members
45,111
Latest member
KetoBurn
Top