One of the reasons why expanding a list can be bad is because it links your MagicReport object too tightly to this list. For example, the Python list supports the following methods:
append count extend index insert pop remove reverse sort
It also contains a number of other operations (adding, comparing using < and > , slicing, etc.).
Are all these operations the things that your MagicReport object really wants to support? For example, the following is legitimate Python:
b = [1, 2] b *= 3 print b
This is a pretty far-fetched example, but if you inherit from a list, your MagicReport object will do the same if someone inadvertently does something like this.
As another example, what if you try to slice a MagicReport object?
m = MagicReport()
You probably expect the slice to be another MagicReport object, but this is actually a list. You need to override __getslice__ to avoid unexpected behavior that is a little painful.
It also makes it difficult for you to change the implementation of the MagicReport object. If you need to do more complex analysis, it often helps to change the data structure into something more suitable for the problem.
If the list is a subclass, you can work around this problem by simply providing new methods append , extend , etc. so that you do not change the interface, but you will not have a clear way to determine which of the list methods are actually used if you are not reading the whole code base. However, if you use a composition and just have a list as a field and create methods for supported operations, you know exactly what needs to be changed.
I actually came across a scenario very similar to yours at work recently. I had an object that contained a collection of “things”, which I first imagined within myself as a list. As the requirements of the project change, I eventually changed the object to an internal use of dict, a custom collection object, and then finally OrderedDict in quick succession. At least in my experience, composition makes it much easier to change how something is implemented, rather than inheritance.
I believe that a list extension can be approved in scenarios where your MagicReport object is a legitimate list in all but the name. If you want to use MagicReport as a list in each individual case and do not plan to change its implementation, then this may be more convenient for a list of subclasses and just do with it.
Although in this case it would be better to just use the list and write the “report” function - I can’t imagine that you need to report the contents of the list more than once and create a custom object using a custom method for this purpose only may be redundant (although this obviously depends on what exactly you are trying to do)