How would I create a custom list class in python?

I like to subclass MutableSequence, as recommended by Alex Martelli. This works well... I frequently need to add custom methods on top of the list I'm building.

#####################################################################
# For more complete methods, refer to UserList() in the CPython source...
# https://github.com/python/cpython/blob/208a7e957b812ad3b3733791845447677a704f3e/Lib/collections/__init__.py#L1215
#####################################################################

try:
    # Python 3
    from collections.abc import MutableSequence
except ImportError:
    # Python 2.7
    from collections import MutableSequence

class MyList(MutableSequence):
    """A container for manipulating lists of hosts"""
    def __init__(self, data=None):
        """Initialize the class"""
        super(MyList, self).__init__()
        if (data is not None):
            self._list = list(data)
        else:
            self._list = list()

    def __repr__(self):
        return "<{0} {1}>".format(self.__class__.__name__, self._list)

    def __len__(self):
        """List length"""
        return len(self._list)

    def __getitem__(self, ii):
        """Get a list item"""
        if isinstance(ii, slice):
            return self.__class__(self._list[ii])
        else:
            return self._list[ii]

    def __delitem__(self, ii):
        """Delete an item"""
        del self._list[ii]

    def __setitem__(self, ii, val):
        # optional: self._acl_check(val)
        self._list[ii] = val

    def __str__(self):
        return str(self._list)

    def insert(self, ii, val):
        # optional: self._acl_check(val)
        self._list.insert(ii, val)

    def append(self, val):
        self.insert(len(self._list), val)

if __name__=='__main__':
    foo = MyList([1,2,3,4,5])
    foo.append(6)
    print(foo)  # <MyList [1, 2, 3, 4, 5, 6]>

    for idx, ii in enumerate(foo):
        print("MyList[%s] = %s" % (idx, ii))

You could extend the list class:

class MyList(list):

    def __init__(self, *args):
        super(MyList, self).__init__(args[0])
        # Do something with the other args (and potentially kwars)

Example usage:

a = MyList((1,2,3), 35, 22)
print(a)
for x in a:
    print(x)

Expected output:

[1, 2, 3]
1
2
3

Your can subclass list if your collection basically behaves like a list:

class MyCollection(list):
    def __init__(self, *args, **kwargs):
        super(MyCollection, self).__init__(args[0])

However, if your main wish is that your collection supports the iterator protocol, you just have to provide an __iter__ method:

class MyCollection(object):
    def __init__(self):
        self._data = [4, 8, 15, 16, 23, 42]

    def __iter__(self):
        for elem in self._data:
            yield elem

This allows you to iterate over any instance of MyCollection.


In Python 3 we have beautiful collections.UserList([list]):

Class that simulates a list. The instance’s contents are kept in a regular list, which is accessible via the data attribute of UserList instances. The instance’s contents are initially set to a copy of list, defaulting to the empty list []. list can be any iterable, for example a real Python list or a UserList object.

In addition to supporting the methods and operations of mutable sequences, UserList instances provide the following attribute: data A real list object used to store the contents of the UserList class.

https://docs.python.org/3/library/collections.html#userlist-objects

Tags:

Python

List