19

I was recently going over a coding problem I was having and someone looking at the code said that subclassing list was bad (my problem was unrelated to that class). He said that you shouldn't do it and that it came with a bunch of bad side effects. Is this true?

I'm asking if list is generally bad to subclass and if so, what are the reasons. Alternately, what should I consider before subclassing list in Python?

Edward Williams
  • 596
  • 7
  • 25
  • 3
    Subclassing list isn't inherently bad, but there are many cases where it's really not what you want to do. We can't answer whether that's the case here unless you give us specifics. – Glenn Maynard Oct 15 '10 at 20:50

4 Answers4

18

The abstract base classes provided in the collections module, particularly MutableSequence, can be useful when implementing list-like classes. These are available in Python 2.6 and later.

With ABCs you can implement the "core" functionality of your class and it will provide the methods which logically depend on what you've defined.

For example, implementing __getitem__ in a collections.Sequence-derived class will be enough to provide your class with __contains__, __iter__, and other methods.

You may still want to use a contained list object to do the heavy lifting.

intuited
  • 23,174
  • 7
  • 66
  • 88
  • 1
    Since Python 3.3+ it has been moved to the [`collections.abc`](https://docs.python.org/3/library/collections.abc.html) module. – xmedeko Sep 09 '16 at 06:39
15

There are no benefits to subclassing list. None of the methods will use any methods you override, so you can have unexpected bugs. Further, it's very often confusing doing things like self.append instead of self.foos.append or especially self[4] rather than self.foos[4] to access your data. You can make something that works exactly like a list or (better) howevermuch like a list you really want while just subclassing object.

Mike Graham
  • 73,987
  • 14
  • 101
  • 130
  • 3
    What if we want to add an attribute to a list? For example, suppose that we have mylist = []. We want something like mylist.x = 3. – riza Oct 17 '10 at 01:15
  • 1
    @Selinap, In a case where I wanted my state to include a list of something and an int, I would still likely use composition. Using inheritance for that opens up confusion in writing, confusion in using, and doesn't really gain you anything. – Mike Graham Nov 13 '10 at 18:38
  • 3
    This seems to be untrue of python 3. These contain [`collections.UserList`](https://docs.python.org/3.4/library/collections.html#collections.UserList) explicitly for this purpose. It even suggests that subclassing from list is possible now: "The need for this class has been partially supplanted by the ability to subclass directly from list;" (I understand this is an old topic and the comments above probably were true while written, just want to make this clear for people finding this question now) – Claude Aug 05 '15 at 08:43
  • 1
    @Claude, There are those that like the abstract fact that since the introduction of new-style classes, subclassing builtins was possible (didn't throw an error), but the fact remains that it's virtually useless. Subclassing list has tons of undefined behavior, and the real behavior is the unhelpful 'nothing is virtual'. It's far more useful in Python 2 or Python 3 to subclass `collections.MutableSequence` or `object`(2)/nothing(3). – Mike Graham Aug 05 '15 at 11:29
  • If I want an iterable with a couple of custom methods and checks, then I'm going to want to sub-class `list` rather than re-implement multiple `list` methods, and re-implement iteration. If there are problems with that that are solved by `UserList` that's good, but whatever happened to OO programming that everyone wants to give up on sub-classing? And the `UserList` docs now say this: "The need for this class has been partially supplanted by the ability to subclass directly from list; however, this class can be easier to work with because the underlying list is accessible as an attribute." – NeilG Oct 02 '22 at 00:59
11

I think the first question I'd ask myself is, "Is my new object really a list?". Does it walk like a list, talk like a list? Or is is something else?

If it is a list, then all the standard list methods should all make sense.

If the standard list methods don't make sense, then your object should contain a list, not be a list.

In old python (2.2?) sub-classing list was a bad idea for various technical reasons, but in a modern python it is fine.

Nick Craig-Wood
  • 52,955
  • 12
  • 126
  • 132
  • As to side effects, he was a bit out of date? The data is contained in a list, but there are a lot of other specific methods I need to throw over the top in order to do a number of things. – Edward Williams Oct 15 '10 at 20:48
  • yes, inherit for "is-a" relationships, compose for pretty much everything else. – Spike Gronim Oct 16 '10 at 00:22
6

Nick is correct. Also, while I can't speak to Python, in other OO languages (Java, Smalltalk) subclassing a list is a bad idea. Inheritance in general should be avoided and delegation-composition used instead.

Rather, you make a container class and delegate calls to the list. The container class has a reference to the list and you can even expose the calls and returns of the list in your own methods. This adds flexibility and allows you to change the implementation (a different list type or data structure) later w/o breaking any code. If you want your list to do different listy-type things then your container can do this and use the plain list as a simple data structure. Imagine if you had 47 different uses of lists. Do you really want to maintain 47 different subclasses? Instead you could do this via the container and interfaces. One class to maintain and allow people to call your new and improved methods via the interface(s) with the implementation remaining hidden.

Joe
  • 3,337
  • 1
  • 14
  • 11