Inheritance and Design Question

0 views
Skip to first unread message

imageguy

unread,
May 27, 2009, 3:58:27 PM5/27/09
to
I have an object the I would like to use as a base class. Some of the
methods I would like to override completely, but others I would simply
like to call the base class method and use the return value in the
child method. The purpose here is to eliminate the duplication of
valuable code in the parent, when I really just need the child to
operate of a results of the parent.

Consider the following two classes;

class Parent(object):
def process(self, value):
retval = "Parent.result('%s')" % value
return retval

class Child(Parent):
def __init__(self):
Parent.__init__(self)

def process(self, value):
retval = "Child.result('%s')" % super(Child, self).process
(value)
return retval

So ....

foo = Child()
print foo.process('the value')
>> Child.result('Parent.result('the value')')

IS there another pattern or idiom that would accomplish this?
This seems a bit 'smelly' to me. Also seems almost the inverse of
decorators, but I am not sure decorators would be appropriate in this
case.

Any help suggestions would be appreciated.

g.

Scott David Daniels

unread,
May 27, 2009, 4:49:23 PM5/27/09
to
Just don't replace the methods you want to use from the superclass
-- it really is that simple. Notice how str is changed below,
but not repr:

class GroupedInt(int):
def __str__(self):
old = super(GroupedInt, self).__str__()
first = old[: len(old) % 3 or 3]
if first == '-':
first = old[: 4]
parts = [first]
parts.extend(old[n : n + 3] for n in
range(len(first), len(old), 3))
return '_'.join(parts)

for n in 1, 12, 123, 1234, 12345, 123456, 1234567:
print '%s\t%s=%r\t%s=%r' % (n, GroupedInt(n), GroupedInt(n),
GroupedInt(-n), GroupedInt(-n))

1 1=1 -1=-1
12 12=12 -12=-12
123 123=123 -123=-123
1234 1_234=1234 -1_234=-1234
12345 12_345=12345 -12_345=-12345
123456 123_456=123456 -123_456=-123456
1234567 1_234_567=1234567 -1_234_567=-1234567

--Scott David Daniels
Scott....@Acm.Org

Matimus

unread,
May 27, 2009, 4:59:33 PM5/27/09
to

From what you have shown, there really is no _good_ reason to use
inheritance at all. Just delegate (which is the decorator pattern,
different from function decorators).

class Inner(object):


def process(self, value):
retval = "Parent.result('%s')" % value
return retval

class Outer(object):
def __init__(self, inner):
self._inner = inner

def process(self, value):
retval = "Outer.result('%s')" % self._inner.process(value)
return retval

This is a silly example, but if you can get the same thing done
without creating a direct dependence between classes then don't. You
will have to construct outer and pass it inner somewhere. If that is a
problem, then just make a factory. In python I implement factories as
just functions most of the time.

The above also encourages reuse. Now you have a decorator that could
be used anywhere.

Matt

Terry Reedy

unread,
May 27, 2009, 5:21:23 PM5/27/09
to pytho...@python.org
imageguy wrote:
> I have an object the I would like to use as a base class. Some of the
> methods I would like to override completely, but others I would simply
> like to call the base class method and use the return value in the
> child method. The purpose here is to eliminate the duplication of
> valuable code in the parent, when I really just need the child to
> operate of a results of the parent.
>
> Consider the following two classes;
>
> class Parent(object):
> def process(self, value):
> retval = "Parent.result('%s')" % value
> return retval
>
> class Child(Parent):
> def __init__(self):
> Parent.__init__(self)

Delete this and the parent __init__ is called directly.


>
> def process(self, value):
> retval = "Child.result('%s')" % super(Child, self).process
> (value)
> return retval

super() was designed for multiple inheritance. The only reason I know
to use it with single inheritance it to save a
global-search-and-replace_with_confirmation if you change the name of
the parent or change parents. Unless I really anticipated such
contigencies, I would probably write Parent.process(self, value).

tjr

Steven D'Aprano

unread,
May 28, 2009, 12:06:39 AM5/28/09
to
On Wed, 27 May 2009 17:21:23 -0400, Terry Reedy wrote:

> super() was designed for multiple inheritance.

Surely you mean that super() was designed for *inheritance*, multiple or
singular? Working with single inheritance is part of the design, not an
accident of implementation.


> The only reason I know
> to use it with single inheritance it to save a
> global-search-and-replace_with_confirmation if you change the name of
> the parent or change parents.

How about these reasons?

(1) If you're subclassing something you didn't write, you might not know
whether it uses multiple or single inheritance.

(2) Even if you do know, you shouldn't care what the implementation of
the parent is. Using super() allows you to be agnostic about the
implementation, while calling Parent.method() directly ties you to a
specific implementation.

(3) Your callers may want to inherit from your class, and if you fail to
use super, you are condemning them to potentially buggy code if they use
multiple inheritance.

(4) Using super() is no harder than avoiding super(). It takes a few
extra characters to type, at worst:

super(MyClass, self).method(args)
Parent.method(self, args)


--
Steven

Andre Engels

unread,
May 28, 2009, 1:53:17 AM5/28/09
to imageguy, pytho...@python.org

I think I would split out the calculation into two methods in this case:

class Parent(object):
def process_essential(self,value):


retval = "Parent.result('%s')" % value
return retval

def processs(self,value):
return process_essential(value)

class Child(Parent):
def process(self,value):
retval = "Child.result('%s')" % process_essential(value)
return retval


--
André Engels, andre...@gmail.com

Carl Banks

unread,
May 28, 2009, 2:44:39 AM5/28/09
to
On May 27, 12:58 pm, imageguy <imageguy1...@gmail.com> wrote:

I see nothing wrong with it, although if it is possible and convenient
to rename the base class method, as Andre Engels suggests, then that's
usually how I'd do it.

Sometimes it's not convenient to choose a different name for the base
class method, such as when you have several subclasses, most of which
don't override the method, but a few do. In that case I'd do it same
way as you did.

One thing that does smell is your use of both old-style base class
access (Parent.__init__(self)) and newer-style (super
(Child,self).process()) in the same class. Pick one method and stick
with it.


Carl Banks

Jean-Michel Pichavant

unread,
May 28, 2009, 6:57:16 AM5/28/09
to imageguy, pytho...@python.org
imageguy wrote:
> I have an object the I would like to use as a base class. Some of the
> methods I would like to override completely, but others I would simply
> like to call the base class method and use the return value in the
> child method. The purpose here is to eliminate the duplication of
> valuable code in the parent, when I really just need the child to
> operate of a results of the parent.
>
> Consider the following two classes;
>
> class Parent(object):
> def process(self, value):
> retval = "Parent.result('%s')" % value
> return retval
>
> class Child(Parent):
> def __init__(self):
> Parent.__init__(self)
>
> def process(self, value):
> retval = "Child.result('%s')" % super(Child, self).process
> (value)
> return retval
>
> So ....
>
> foo = Child()
> print foo.process('the value')
>
>>> Child.result('Parent.result('the value')')
>>>
Try this

class Parent(object):

def process(self, value):
retval = "%s.result('%s')" % (self.__class__.__name__, value)
return retval

class Child(Parent):
def __init__(self):
Parent.__init__(self)

foo = Child()
print foo.process('the value')

>>> Child.result('the value'')

Of course you cannot see the inheritance in the result, but I'm assuming you wanted only the instance class to be displayed.

Jean-Michel

Reply all
Reply to author
Forward
0 new messages