[Tutor] Multiple inheritance for mixin attributes
Steven D'Aprano
steve at pearwood.info
Mon Aug 16 13:01:53 CEST 2010
On Mon, 16 Aug 2010 05:01:58 pm Knacktus wrote:
> Hello everyone,
>
> I've got a question about class design. I want to model classes like
> these (examples):
>
> #####################################################################
> class BaseItem(object):
> def __init__(self, ident, name, description):
> self.ident = ident
> self.name = name
> self.description = description
>
> class DataSourceItem(object):
> def __init__(self, ident, name, description, data_source):
> self.ident = ident
> self.name = name
> self.description = description
> self.data_source = data_source
That's a clear job for single inheritance:
class DataSourceItem(BaseItem):
def __init__(self, ident, name, description, data_source):
BaseItem.__init__(self, ident, name, description)
self.data_source = data_source
Note: there's a BIG question mark as to whether you should use super()
or not when inheriting methods. I've previously defended the use of
super() even in single-inheritance classes, where it is not strictly
necessary but does no harm. However in this case, the function
signature of DataSourceItem and BaseItem are different, which is a
clear signal *not* to use super(). But if you're brave, here's a
version that uses super():
class DataSourceItem(BaseItem):
def __init__(self, ident, name, description, data_source):
super(DataSourceItem, self).__init__(ident, name, description)
self.data_source = data_source
Is this safe? Well, probably, for the simple class hierarchy you enter.
But if you extend the class hierarchy with more sibling and child
classes, perhaps not.
> class BaseItemCollection(list):
> def __init__(self, ident, name, description):
> self.ident = ident
> self.name = name
> self.description = description
> def default_version(self):
> return self[-1]
That's a clear job for composition:
class BaseItemCollection(list):
def __init__(self, ident, name, description):
self.data = BaseItem(ident, name, description)
def default_version(self):
return self[-1]
> class BaseDataSourceItemCollection(list):
> def __init__(self, ident, name, description, data_source):
> self.ident = ident
> self.name = name
> self.description = description
> self.data_source = data_source
> def default_version(self):
> return self[-1]
This one isn't clear. You could inherit either directly from list:
class BaseDataSourceItemCollection(list):
def __init__(self, ident, name, description, data_source):
self.data = DataSourceItem(
ident, name, description, data_source)
def default_version(self):
return self[-1]
or from BaseItemCollection:
class BaseDataSourceItemCollection(BaseItemCollection):
def __init__(self, ident, name, description, data_source):
BaseItemCollection.__init__(self, ident, name, description)
self.data_source = data_source
Which such trivially small classes, there's no real advantage or
disadvantage to either.
Of course, you could use multiple inheritance, but that opens a whole
rat's nest of difficulties. Even though Python makes it easy to
implement multiple-inheritance, it is full of pitfalls for the unwary,
and even the wary, so you should always consider whether you *really*
need it.
Other alternatives are traits and generic functions:
http://www.artima.com/weblogs/viewpost.jsp?thread=246488
http://www.artima.com/weblogs/viewpost.jsp?thread=237764
Lastly, I should mention automatic delegation as an alternative to
inheritance. It's not clear to me that this would be either useful or
necessary for your classes, but I'll mention it so you can google for
more information if you are interested.
--
Steven D'Aprano
More information about the Tutor
mailing list