473,387 Members | 1,528 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

Question about subclassing - version 2

Hi all

I recently posted a question about subclassing. I did not explain my
full requirement very clearly, and my proposed solution was not pretty.
I will attempt to explain what I am trying to do more fully, and
describe a possible solution. It is still not pretty, so I would
appreciate any comments.

I have a base class (ClassA), which is an abstract class. Most of the
methods and attributes are common to all subclasses, so there is not
much they have to override.

I have a subclass (ClassB) of my base class, which is also abstract. It
represents a subset of ClassA, and overrides some of its methods. When
I create a concrete class (is that the correct term?) I subclass either
from ClassA or from ClassB.

Now I want to represent a different subset of ClassA, which overrides
some of its methods. This subset can apply to ClassB as well as to
ClassA.

In pseudo terms, I want ClassA1, ClassA2, ClassB1, and ClassB2 where A1
is the base class, B overides some methods, and 2 overrides other
methods, and I want to subclass from any of them.

My original solution involved passing 1 or 2 as an argument, and
putting some code into __init__ which redefined certain methods if it
received a 2. This worked, but it meant that I could not then easily
redefine the method again in a concrete class.

My new idea is to use multiple inheritance. This is how it would work.

class ClassA(object):
def __init__(self):
pass
def test1(self):
print 'Base method 1'
def test2(self):
print 'Base method 2'

class ClassB(ClassA):
def __init__(self):
ClassA.__init__(self)
def test1(self):
print 'Overriding method 1'

class Class2(object):
def test2(self):
print 'Overriding method 2'

Now I can set up the following concrete classes -

class ClassA1(ClassA):
def __init__(self):
ClassA.__init__(self)

class ClassA2(Class2,ClassA):
def __init__(self):
ClassA.__init__(self)

class ClassB1(ClassB):
def __init__(self):
ClassB.__init__(self)

class ClassB2(Class2,ClassB):
def __init__(self):
ClassB.__init__(self)

Now if I do the following, I get the results shown, which is what I
want -

ClassA1().test1() - 'Base method 1'
ClassA1().test2() - 'Base method 2'
ClassB1().test1() - 'Overriding method 1'
ClassB1().test2() - 'Base method 2'
ClassA2().test1() - 'Base method 1'
ClassA2().test2() - 'Overriding method 2'
ClassB2().test1() - 'Overriding method 1'
ClassB2().test2() - 'Overriding method 2'

Now for the real test -

class ClassC3(Class2,ClassB):
def __init__(self):
ClassB.__init__(self)
def test1(self):
print 'Overriding method 1 from ClassC3'
def test2(self):
print 'Overriding method 2 from ClassC3'

ClassC3().test1() - 'Overriding method 1 from ClassC3'
ClassC3().test2() - 'Overriding method 2 from ClassC3'

So it works. However, using multiple inheritance is not ideal, and I
believe it is not even supported in some languages. Can anyone suggest
a better way of tackling this problem?

Thanks

Frank Millman

Sep 8 '06 #1
10 1177
Frank Millman, just a short note, more expert people can give you
better answers. There aren't abstract classes in Python. They are all
concrete. You may have classes with undefined methods (they may raise
NotImplementedError).
Multiple inheritance isn't supported by Java and Ruby, but it is
supported by C++ and Python, so you can use it in Python.
There are also ways of mixing methods. You may define methods, and then
lists of methods to add to your classes.

Bye,
bearophile

Sep 8 '06 #2

be************@lycos.com wrote:
Frank Millman, just a short note, more expert people can give you
better answers. There aren't abstract classes in Python. They are all
concrete. You may have classes with undefined methods (they may raise
NotImplementedError).
Multiple inheritance isn't supported by Java and Ruby, but it is
supported by C++ and Python, so you can use it in Python.
There are also ways of mixing methods. You may define methods, and then
lists of methods to add to your classes.

Bye,
bearophile
I use the term 'abstract class' in the abstract sense :-)

Say I have three classes where 90% of the attributes and methods are
common. It makes sense to create a base class with these attributes and
methods, and turn each of the three classes into a subclass which
inherits from the base class and overrides the bits that are unique to
each one.

This is what I call an abstract class. Maybe there is a more correct
term.

Frank

Sep 8 '06 #3
Frank Millman wrote:
Hi all

I recently posted a question about subclassing. I did not explain my
full requirement very clearly, and my proposed solution was not pretty.
I will attempt to explain what I am trying to do more fully, and
describe a possible solution. It is still not pretty, so I would
appreciate any comments.

I have a base class (ClassA), which is an abstract class. Most of the
methods and attributes are common to all subclasses, so there is not
much they have to override.

I have a subclass (ClassB) of my base class, which is also abstract. It
represents a subset of ClassA, and overrides some of its methods. When
I create a concrete class (is that the correct term?) I subclass either
from ClassA or from ClassB.

Now I want to represent a different subset of ClassA, which overrides
some of its methods. This subset can apply to ClassB as well as to
ClassA.

In pseudo terms, I want ClassA1, ClassA2, ClassB1, and ClassB2 where A1
is the base class, B overides some methods, and 2 overrides other
methods, and I want to subclass from any of them.

My original solution involved passing 1 or 2 as an argument, and
putting some code into __init__ which redefined certain methods if it
received a 2. This worked, but it meant that I could not then easily
redefine the method again in a concrete class.

My new idea is to use multiple inheritance. This is how it would work.

class ClassA(object):
def __init__(self):
pass
def test1(self):
print 'Base method 1'
def test2(self):
print 'Base method 2'

class ClassB(ClassA):
def __init__(self):
ClassA.__init__(self)
def test1(self):
print 'Overriding method 1'

class Class2(object):
def test2(self):
print 'Overriding method 2'
To be pedantic, Class2.test2 is not overridding anything, since there's
no "test2" method in it's parent class.
Now I can set up the following concrete classes -

class ClassA1(ClassA):
def __init__(self):
ClassA.__init__(self)
If that's the only thing you do in the __init__, then don't bother write
an init method at all.
class ClassA2(Class2,ClassA):
def __init__(self):
ClassA.__init__(self)
May I suggest having a look at super() ?
class ClassB1(ClassB):
def __init__(self):
ClassB.__init__(self)

class ClassB2(Class2,ClassB):
def __init__(self):
ClassB.__init__(self)

Now if I do the following, I get the results shown, which is what I
want -

ClassA1().test1() - 'Base method 1'
ClassA1().test2() - 'Base method 2'
ClassB1().test1() - 'Overriding method 1'
ClassB1().test2() - 'Base method 2'
ClassA2().test1() - 'Base method 1'
ClassA2().test2() - 'Overriding method 2'
ClassB2().test1() - 'Overriding method 1'
ClassB2().test2() - 'Overriding method 2'

Now for the real test -

class ClassC3(Class2,ClassB):
def __init__(self):
ClassB.__init__(self)
def test1(self):
print 'Overriding method 1 from ClassC3'
def test2(self):
print 'Overriding method 2 from ClassC3'

ClassC3().test1() - 'Overriding method 1 from ClassC3'
ClassC3().test2() - 'Overriding method 2 from ClassC3'

So it works. However, using multiple inheritance is not ideal,
Why so ? Multiple inheritence is a pretty useful tool - but it can
become tricky very soon. IMHO, it's best use is for mixin classes...
and I
believe it is not even supported in some languages.
A lot of things aren't even supported in some languages !-)
Can anyone suggest
a better way of tackling this problem?
Not out of my hat. Just a few considerations on Python and OO: Python
being dynamically typed, inheritence is only about sharing
implementation. There's another way to do share implementation -
composition/delegation. It's more flexible, and can avoid "cartesian
product" multiplication of classes. It's also less advertised than
inheritance - probably because of "some languages" that fail to offer
any support for it. The good news here is that Python makes it a breeze,
thanks to the __getattr__/__setattr__ hooks. Now I don't know if it
makes any sense WRT/ your current problem...
--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Sep 8 '06 #4

Bruno Desthuilliers wrote:
Frank Millman wrote:
be************@lycos.com wrote:
There aren't abstract classes in Python. They are all
concrete.
(snip)
I use the term 'abstract class' in the abstract sense :-)

Say I have three classes where 90% of the attributes and methods are
common. It makes sense to create a base class with these attributes and
methods, and turn each of the three classes into a subclass which
inherits from the base class and overrides the bits that are unique to
each one.

This is what I call an abstract class. Maybe there is a more correct
term.

Depends if instanciating this base class would make any sense.
It would not make sense, no.

I have not gone to the trouble of raising NotImplementedError - the
methods that the subclasses *must* override just have a 'pass'
statement. I guess it would be more correct to raise the error, as it
would give me a quicker indication of an error if I happened to omit
one, but in practice I would find out pretty quickly anyway.

Frank

Sep 8 '06 #5
Le vendredi 08 septembre 2006 09:51, be************@lycos.com a écrit*:
Frank Millman, just a short note, more expert people can give you
better answers. There aren't abstract classes in Python. They are all
concrete.
Really ? This is like saying there is no singleton in Python...

class AbstractClass(object) :

def __init__(self) : raise RuntimeError('Ths class is an abstract one !')

The abstract class can then define APIs (methods which raise
NotImplementedError) and/or logic (fully implemented methods).
With this scheme you are not stuck to the "API only" usage of abstract classes
like in Java nad its interfaces.
You may have classes with undefined methods (they may raise
NotImplementedError).
C++ "pure virtual methods" is only the C++ way of doing something which is a
more general concept in OOP.
--
_____________

Maric Michaud
_____________

Aristote - www.aristote.info
3 place des tapis
69004 Lyon
Tel: +33 426 880 097
Sep 8 '06 #6
Le vendredi 08 septembre 2006 10:15, Bruno Desthuilliers a écrit*:
You
mentioned NotImplementedError, which is indeed the usual way to make
something "abstract" in Python.
Hummm, some more thoughts about this.

I can imagine class hierarchies where the presence of not implemented methods
doesn't mean that the class is actually an abstract one. Even if partial
implementation is not a common scheme it can save you from writing a lot of
classes.

For example :

class car : #abstract
def accelerate() : raise NotimplementedError
def getBaseBuildPrice() : raise NotimplementedError
def getOptionsPrice() : raise NotimplementedError
def getPublicPrice() : raise NotimplementedError

class SerieA(car) :
"""abstract, it's before the car
get out of the factory"""
def accelerate() : ...
def getBaseBuildPrice() : ...

class CrashTestVendorSerieA(SerieA) :
"""concrete, but doesn't
implement getPublicPrice"""
def getOptionsPrice() : ...

class CommercialSerieA(SerieA) :
def getOptionsPrice() : ...
def getPublicPrice() : ....

Doing the same with more traditional object design give :

class car : #abstract
def accelerate() : raise NotimplementedError
def getBaseBuildPrice() : raise NotimplementedError

class SerialCar : #abstract
def getOptionsPrice() : raise NotimplementedError

class ComercialCar : #abstract
def getPublicPrice() : raise NotimplementedError

class SerieA(car, SeriialCar) : #abstract
def accelerate() : ...
def getBaseBuildPrice() : ...

class CrashTestVendorSerieA(SerieA) : # concrete
def getOptionsPrice() : ...

class CommercialSerieA(SerieA, CommercialCar) : # concrete
def getOptionsPrice() : ...
def getPublicPrice() : ...

And this can become a true spider net for more complicated cases. Obviously,
in practice we will choose alternatives to inheritance (strategies,
visitors, ...) to work with such complex situations, but it seems to me that
partial implementation is not a bad choice, specifically in regard to duck
typing.
--
_____________

Maric Michaud
_____________

Aristote - www.aristote.info
3 place des tapis
69004 Lyon
Tel: +33 426 880 097
Sep 8 '06 #7
Frank Millman wrote:
Bruno Desthuilliers wrote:
>Frank Millman wrote:
>>be************@lycos.com wrote:
There aren't abstract classes in Python. They are all
concrete.
(snip)
>>I use the term 'abstract class' in the abstract sense :-)

Say I have three classes where 90% of the attributes and methods are
common. It makes sense to create a base class with these attributes and
methods, and turn each of the three classes into a subclass which
inherits from the base class and overrides the bits that are unique to
each one.

This is what I call an abstract class. Maybe there is a more correct
term.
Depends if instanciating this base class would make any sense.

It would not make sense, no.

I have not gone to the trouble of raising NotImplementedError - the
methods that the subclasses *must* override just have a 'pass'
statement. I guess it would be more correct to raise the error, as it
would give me a quicker indication of an error if I happened to omit
one, but in practice I would find out pretty quickly anyway.
Mmm... My own experience is that methods that *must* be redefined are
better raising NotImplementedError. Makes things more obvious IMHO.

Now there are of course methods that are only provided as hooks - here
it's ok to have some no-op default behaviour.

My 2 cents
Frank

--
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'o****@xiludom.gro'.split('@')])"
Sep 8 '06 #8

Bruno Desthuilliers wrote:
Frank Millman wrote:

I have not gone to the trouble of raising NotImplementedError - the
methods that the subclasses *must* override just have a 'pass'
statement. I guess it would be more correct to raise the error, as it
would give me a quicker indication of an error if I happened to omit
one, but in practice I would find out pretty quickly anyway.

Mmm... My own experience is that methods that *must* be redefined are
better raising NotImplementedError. Makes things more obvious IMHO.
Can't argue with that. I have just gone through my app and changed them
all :-)

Frank

Sep 8 '06 #9
Frank Millman wrote:
Bruno Desthuilliers wrote:
>>Frank Millman wrote:
>>>I have not gone to the trouble of raising NotImplementedError - the
methods that the subclasses *must* override just have a 'pass'
statement. I guess it would be more correct to raise the error, as it
would give me a quicker indication of an error if I happened to omit
one, but in practice I would find out pretty quickly anyway.

Mmm... My own experience is that methods that *must* be redefined are
better raising NotImplementedError. Makes things more obvious IMHO.


Can't argue with that. I have just gone through my app and changed them
all :-)
Yup, if a thing can't go wrong, it won't

regards
Steve
--
Steve Holden +44 150 684 7255 +1 800 494 3119
Holden Web LLC/Ltd http://www.holdenweb.com
Skype: holdenweb http://holdenweb.blogspot.com
Recent Ramblings http://del.icio.us/steve.holden

Sep 8 '06 #10
Maric Michaud a écrit :
Le vendredi 08 septembre 2006 10:15, Bruno Desthuilliers a écrit :
>>You
mentioned NotImplementedError, which is indeed the usual way to make
something "abstract" in Python.


Hummm, some more thoughts about this.

I can imagine class hierarchies where the presence of not implemented methods
doesn't mean that the class is actually an abstract one.
I can imagine this too - as well as I can imagine the nightmarish
spaghetti code that could use this class hierarchie.
Even if partial
implementation is not a common scheme it can save you from writing a lot of
classes.
A partial implementation should return default values, not raise (aka
NullObjectPattern). Well, IMHO at least.

(snip)
And this can become a true spider net for more complicated cases. Obviously,
in practice we will choose alternatives to inheritance (strategies,
visitors, ...)
Composition/delegation...
to work with such complex situations,
Indeed.
Sep 9 '06 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: BJörn Lindqvist | last post by:
A problem I have occured recently is that I want to subclass builtin types. Especially subclassing list is very troublesome to me. But I can't find the right syntax to use. Take for example this...
11
by: Brent | last post by:
I'd like to subclass the built-in str type. For example: -- class MyString(str): def __init__(self, txt, data): super(MyString,self).__init__(txt) self.data = data
7
by: Guinness Mann | last post by:
I have a class that I use throughout my application, and I store collections of my class in an ArrayList. To avoid some really ugly casting I'd like to subclass ArrayList to get a typed version. ...
6
by: Peter Oliphant | last post by:
I just discovered that the ImageList class can't be inherited. Why? What could go wrong? I can invision a case where someone would like to add, say, an ID field to an ImageList, possible so that...
11
by: D | last post by:
I have a client application that I want (behind the scenes) to check and make sure a remote host is up (i.e. by ping or TCP connect). I'm assuming that, since I want this to go on "unknowingly" to...
6
by: Jackson | last post by:
I've got an inheritance question and was hoping brighter minds could guide me. I am in the strange situation where some of the methods in a subclass are actually more general than methods in a...
3
by: arncota | last post by:
Hi, I created a UserControl, and created its UI with the designer. Next, I wanted to create a subclass of that UserControl, with a new UI. But when I open it in the designer, I see the UI...
16
by: manatlan | last post by:
I've got an instance of a class, ex : b=gtk.Button() I'd like to add methods and attributes to my instance "b". I know it's possible by hacking "b" with setattr() methods. But i'd like to do...
5
by: Ray | last post by:
Hi all, I am thinking of subclassing the standard string class so I can do something like: mystring str; .... str.toLower (); A quick search on this newsgroup has found messages by others
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.