0

I'm trying to create a custom list subclass that inherits all aspects of the list class, except that its append method sorts the list each time a new object is added.

So far, I have something like this:

class CommentList(list):
    def append(self, other):
         return self.data_list.append(other)

I'm not sure how I can introduce the sort functionality to this and how I can improve the method above.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
christina
  • 1
  • 1
  • 1
  • Here is good explanation of why you shouldn't inherit from list http://stackoverflow.com/questions/21692193/why-not-inherit-from-listt – Andrey Mar 24 '15 at 22:48
  • @Andrey: That's a C# explanation. Moreover, it's not clear to me that the accepted answer applies to OP's question. In any event, it would be more useful to tell OP to inherit from `collections.abc.MutableSequence` instead of just saying "don't do that." – Kevin Mar 24 '15 at 22:50
  • 1
    @Andrey, this case doesn't match that scenario. Here OP wants to extend the functionality of the List to make it remain sorted; the result would still be a list. Whether List is the right base class for this case is a different question and Kevin may be right (although I'm not familiar with the class he mentions) – Holloway Mar 24 '15 at 22:52
  • @Kevin explanation is abstract and has very little to specifics of C#. It is generally bad idea to inherit business logic classes from list/List/MutableSequence. It makes sense only if you are implementing some new type of container. Composition over inheritance. – Andrey Mar 24 '15 at 22:53
  • @Andrey: We don't know this is a business logic class. – Kevin Mar 24 '15 at 22:53
  • @Kevin what kind of class is CommentList? It doesn't sound like generic container, it's function is in the name. – Andrey Mar 24 '15 at 22:54
  • @Andrey: *shrug*. I'd guess it's a poor-man's heap or B+Tree. I would recommend OP look into the `heapq` module for the former. – Kevin Mar 24 '15 at 22:55
  • 1
    Furthermore, inheriting business logic classes from MutableSequence is the *whole point*; it's the Python equivalent to IList, except it has default implementations of most of the methods. – Kevin Mar 24 '15 at 23:00

5 Answers5

8

The simplest possible implementation would be:

class CommentList(list):

    def append(self, val):
        super(CommentList, self).append(val)
        self.sort()

This does what you want:

>>> l = CommentList((2, 3, 4))
>>> l.append(5)
>>> l
[2, 3, 4, 5]
>>> l.append(1)
>>> l
[1, 2, 3, 4, 5]

But note that there are other ways to get data into the list (__add__, extend, __setitem__); should they involve sorting? Should e.g. a slice of a CommentList be another CommentList, or a vanilla list? A CommentList looks exactly like a vanilla list, as it inherits the __repr__, but this could be misleading. Subclassing built-in types can be complex; you should really start from the MutableSequence abstract base class, instead.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
2

Just use a super call then add your sort function call:

class CommentList(list):
    def append(self, other):

        # call the append of the parent class
        # which of course is the builtin list

        super(CommentList, self).append(other)

        # then call the sort method that we 
        # just inherited from the parent 

        self.sort() # sort after using append
Malik Brahimi
  • 16,341
  • 7
  • 39
  • 70
0
class CommentList(list):
    def append(self, other):
         r = super(CommentList, self).append(other)
         self.sort()
         return r
Ghopper21
  • 10,287
  • 10
  • 63
  • 92
  • Nothing was mentioned about a return. – Malik Brahimi Mar 24 '15 at 22:57
  • 1
    @MalikBrahimi - just generally a good habit to return whatever the superclass returns when you override a method by default. Currently append returns None and this behavior is inherited. If for whatever unforseen reason, append's return behavior changed in a future version of Python, this code would inherit such change. – Ghopper21 Mar 24 '15 at 22:59
0

In my opinion, it would be pretty "unpythonic" to do this. There is no reason to use inheritance, you could simply return a sorted list after each append.

That said, often there is no need for a list to be sorted until it has been filled. In that case, build your list, then just set up a sorted_list by assigning sorted(original_list) to it.

In either event, you are going to have to determine what it means for a list to be sorted.

You also have to worry about what to do with:

a = list () a.append (19) a.append ('my birthday')

Fred Mitchell
  • 2,145
  • 2
  • 21
  • 29
0

You can do this, but it is almost certainly not what you want. Among other reasons, append() is only one way that list elements get changed. setitem(), insert(), and extend() for instance. If you want "the list is sorted" to be an invariant, you need to override all of those methods. Chances are you don't intend to use those methods. If so, you could just make an object that contains a list, and only exposes the methods you want.

If performance is an issue, you would want to change to a data structure like a heap or tree that directly supports maintaining sorted order.

If you really want an object that works like a list but has the extra feature that append triggers a sort, what you have will work, but that is an odd behavior.

Evan
  • 2,217
  • 15
  • 18