45

I want to implement a custom list class in Python as a subclass of list. What is the minimal set of methods I need to override from the base list class in order to get full type compatibility for all list operations?

This question suggest that at least __getslice__ needs to be overridden. From further research, also __add__ and __mul__ will be required. So I have this code:

class CustomList(list):
    def __getslice__(self,i,j):
        return CustomList(list.__getslice__(self, i, j))
    def __add__(self,other):
        return CustomList(list.__add__(self,other))
    def __mul__(self,other):
        return CustomList(list.__mul__(self,other))

The following statements work as desired, even without the overriding methods:

l = CustomList((1,2,3))
l.append(4)                       
l[0] = -1
l[0:2] = CustomList((10,11))    # type(l) is CustomList

These statements work only with the overriding methods in the above class definition:

l3 = l + CustomList((4,5,6))    # type(l3) is CustomList
l4 = 3*l                        # type(l4) is CustomList
l5 = l[0:2]                     # type(l5) is CustomList

The only thing I don't know how to achieve is making extended slicing return the right type:

l6 = l[0:2:2]                   # type(l6) is list

What do I need to add to my class definition in order to get CustomList as type of l6?

Also, are there other list operations other than extended slicing, where the result will be of list type instead of CustomList?

10
  • 11
    @Johnsyweb: CustomList is intended to hold data of a specific type, and will have additional parameters and methods applying to these data (which I left out for the question). Commented Nov 18, 2011 at 9:24
  • 1
    Silvado, just out of curiosity, can you please give more information on CustomList and some details about the data? Inheriting from base types in Python is a VERY unappreciated practice, so maybe there is a way to do what you want to do without inheriting from list. Commented Nov 18, 2011 at 10:01
  • 8
    BasicWOlf: Why is subclassing from base types unappreciated? Commented Nov 18, 2011 at 10:04
  • 1
    Because built-in types are optimized to work as they are. You can never assume what will be the result of overriding some of the methods and leaving other methods intact. -- Subclassing built-in types is a very common behaviour of people with Ruby background. DON'T do that in Python. Commented Nov 18, 2011 at 10:10
  • 1
    Absolutely right. Or just items = datalist.items :) Commented Nov 18, 2011 at 11:53

5 Answers 5

30

Firstly, I recommend you follow Björn Pollex's advice (+1).

To get past this particular problem (type(l2 + l3) == CustomList), you need to implement a custom __add__():

   def __add__(self, rhs):
        return CustomList(list.__add__(self, rhs))

And for extended slicing:

    def __getitem__(self, item):
        result = list.__getitem__(self, item)
        try:
            return CustomList(result)
        except TypeError:
            return result

I also recommend...

pydoc list

...at your command prompt. You'll see which methods list exposes and this will give you a good indication as to which ones you need to override.

Sign up to request clarification or add additional context in comments.

5 Comments

Thanks. With the second hint, I saw all non-underscore methods for list (e.g. extend) etc.. I haven't tried all of them, but since these all act in place, I wouldn't expect any type problems there. So only extended slicing seems to remain as my problem...
This implementation of __getitem__ raises TypeError: 'int' object is not iterable on either l[0] or l[0:2:2]. So I guess I need to distinguish at least whether item is a slice or individual index.
I suggested an edit of the answer in this direction which seems to work.
Great, this works as expected. Just out of curiosity, what about implementation efficiency if I access mostly single items aka l[0]? In this case, I will always run into the exception handling code.
I'm following the Python EAFP idiom. Premature optimization... and all that...
27

You should probably read these two sections from the documentation:

Edit: In order to handle extended slicing, you should make your __getitem__-method handle slice-objects (see here, a little further down).

3 Comments

Thanks for the pointer. So I learnt that multiplication and extended slicing is also an issue. I extended my code to get addition and multiplication right (see edit), but am still stuck with extended slicing.
The second link is broken.
Indeed, this section doesn't seem to exist in the Python 3 documentation, so it's now pointing at the Python 2 docs.
11

Possible cut-the-gordian-knot solution: subclass UserList instead of list. (Worked for me.) That is what UserList is there for.

1 Comment

This is by far the easiest and least error-prone solution for my use-case. Checkout the docs for more info: docs.python.org/3/library/collections.html#collections.UserList
0

As a slight modification to Johnsywebs answer. I would only convert to a CustomList if item is a slice. Otherwise CustomList(["ab"])[0] would give you CustomList(["a", "b"]) which is not what you want. Like this:

def __getitem__(self, item):
    result = list.__getitem__(self, item)
    if type(item) is slice:
        return CustomList(result)
    else:
        return result

Comments

0

The collections.UserList class is the perfect solution for you. Just subclass CustomList from this. Then all methods producing a new list will create CustomList objects. You won't have to override any list methods! See collections

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.