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?)
 
    