I am trying to better understand composition vs inheritance in python so I have crafted a hopefully simple example.
Suppose I want to implement a class TitledList
that is intended to behave just like a standard list, but with an additional attribute title
intended to hold a string containing the name of the list. The __repr__
and __str__
methods would likely have to be reimplemented to incorporate the title, but otherwise I'd like to retain all the native functionality of list
. Initializers would accept an optional keyword-only argument title
.
I can see two approaches to creating this class. I could go the composition route, and define a class with two attributes, .contents
(a regular list) and .title
. That would presumably look something along the lines of
class TitledList:
def __init__(self, contents=[], *, title=None):
self.contents = list(contents)
self.title = title
But I'm not sure how I would go about cribbing all the methods of list
so I don't have to constantly be referring to my_titled_list.contents
all over the place or reimplement all the list methods I use.
The other alternative is to do the thing that everyone on the whole Internet says not to do, and inherit from the list
class. I think in that case I would do the initializer like this?
class TitledList(list):
def __init__(self, iterable=[], *, title=None):
super().__init__(iterable)
self.title = title
This seems a lot more straightforward to me. But surely everyone on the whole Internet says not to extend list
for a reason.
What are the pros and cons here? Is there a simple way to make the composition solution work the way I intuitively want? Are there lots of drawbacks to the inheritance solution that I don't understand? Is there some third option I should be considering (UserList
?)
There are several ways to do it.
Subclass collections.UserList
instead of list
. This is basically a wrapper around list
designed to be extensible.
Subclass collections.abc.MutableSequence
and implement all of the required abstract methods. This might be useful if you want to define a totally new sequence-like class.
Subclass list
. This might actually be fine in limited scenarios like your TitledList
example, where you're just adding a new attribute. But if you want to ovverride list
's existing methods then this may not be a good idea.
Create a new object with a list attribute. This is simple and easy to understand, but might be inconvenient. It all depends on your use case.
Reference: Trey Hunner: The problem with inheriting from dict and list in Python