The UserList class in the collections module provides a wrapper around the built-in list type to aid in customization of the list behavior. It is useful for creating specialized types of list objects that have their own properties and methods.

Basically, UserList objects has methods similar to that of standard lists. It is meant to be inherited from by custom lists that needs to have the functionality of standard list in addition to others that are unique to them.

When we use UserList objects directly(without inheritance), the functionality is literally just similar to that of standard lists.

use UserList objects directly.

#import the class
from collections import UserList

L = UserList()

L.append(0)
L.append(10)
L.append(20)
L.append(30)
L.append(40)

print(L[0])
print(L[1])
print(L.pop())

As you can see from the above snippet, in their basic form, UserList objects have methods and functionality like that of standard lists. Sub-classing the class allows us to override or extend the behavior of the standard list to suit our requirements.

Create custom lists

The following example subclasses the UserList class to create a simple list of fixed length. A fixed list has a maximum length beyond which no more elements can be added. We will override some list methods to achieve this functionality.

from collections import UserList

class FixedList(UserList): 
    def __init__(self, length): 
      self.length = length 
      super().__init__()

    def insert(self, index, value):
      if len(self) == self.length: 
        raise ValueError('List full!')
      super().insert(index, value)

    def append(self, value): 
       if len(self) == self.length: 
         raise ValueError('List full!')
       super().append(value)

    def maxlen(self):
      return self.length
        

L = FixedList(5)
print("maximum length: ", L.maxlen())
L.append(10)
L.append(15)
L.append(20)
L.append(25)
L.append(30)
print(L)
L.append(35) #the list is full

In the above example, we have overridden three list methods, __init__(), insert(), and append(), to create  a simple fixed-length list that does not allow insertion when the maximum length is reached.  We also defined a custom method, maxlen() which returns the list's maximum length.

The above is just a simple implementation to demonstrate how UserList can be sub-classed, a thorough implementation of fixed-length list would have to deal with more lower-level methods like __setitem__() and __delitem__(), instead of the ones we used i.e insert() and append()

create a homogenous list

By default, standard lists are heterogenous meaning that they can contain items of different types e.g ['Pynerds', 1, [1, 2], 2.0]. In the following example we will use the UserList class to create a list that can only contain objects belonging to one type that is specified during instantiation.

from collections import UserList

class HomoList(UserList):
      def __init__(self, list_type):
          self.list_type = list_type
          super().__init__()

      def append(self, value): 
         if isinstance(value, self.list_type):
           super().append(value)
         else: 
           raise TypeError(f'"{value}" is of unsupported type.')

#A list of ints
L = HomoList(int)
L.append(10)
L.append(20)
L.append(30)
L.append(40)
L.append(50)
print(L)
L.append("ten") #unsupported type "str"