Skip to content

Python UserList – Custom Python Lists with collections

Python UserList - Custom Python Lists with collections Cover Image

Building custom lists allows you to define powerful programs, by extending on the functionality of normal Python lists. You can easily build new lists that have custom behavior or new functionalities, which build on top of regular Python lists. In this tutorial, you’ll learn how to use the Python collections UserList class to create custom lists. You’ll also learn how to build your own custom list, by building a list that allows only numbers and allows you to build custom methods that can square all values.

By the end of this tutorial, you’ll have learned the following:

  • How to build custom Python lists using the UserList class
  • How to understand common use cases for the UserList class by building an example custom list

Understanding the Python collections UserList Class

The UserList class has been included in Python since version 1.6, however, it was moved to the collections module in Python 3. We can use the UserList class to inherit from a list to enhance or modify its default behavior. In particular, the class simply subclasses, rather than instantiates.

The class was made available before it was possible to simply inherit from the list class itself. However, it still provides some helpful benefits. For example, you can access the underlying data using the .data attribute, rather than relying on calling the super() function.

The class created a data attribute, which stores the contents of the underlying list. This allows you to build custom methods and behavior that have access to the underlying data.

Let’s see how the class is defined and how to create a simple UserList:

# Creating a UserList
from collections import UserList

class Custom(UserList):
    pass

custom_list = Custom([1, 2, 3, 4])
print(custom_list)

# Returns:
# [1, 2, 3, 4]

In the example above, we created a UserList that doesn’t modify the behavior of the regular list. This example was merely meant to illustrate that the custom list inherits all default behavior from a normal Python list.

This means that, for example, you could call all normal list methods on our custom_list, such as .extend().Let’s now dive into an example of how to create a custom list using the UserList class.

Creating a Custom List with Python UserList

In our previous example, we created a UserList list which didn’t modify a list’s behavior at all. However, let’s dive into some more advanced use cases. We’ll create a special list that accepts only numbers. It goes further, however, to also provide a method to square all numbers in the list.

By default, Python lists are heterogenous, meaning that they can hold different types of data. For example, we can create a list that looks like this: ['datagy', 1, 2, 3]. In this sample list, we have a string as well as integers.

Let’s see how we can use the UserList class to create a custom Python list:

# Creating a Custom List
from collections import UserList

class NumberList(UserList):
    def __init__(self, iterable):
        super().__init__(
            item for item in iterable if type(item) in [int, float])

    def __setitem__(self, index, item):
        if type(item) in [int, float]:
            self.data[index] = item
        else:
            raise TypeError('Item must be a number.')

    def append(self, item):
        if type(item) in [int, float]:
            self.data.append(item)
        else:
            raise TypeError('Item must be a number.')

    def square_values(self):
        for item in self.data:
            print(item ** 2)


custom_list = NumberList([1, 2, 3, 'datagy'])

print(custom_list)

# Returns: [1, 2, 3]

In the code block above, we created a UserList. There’s a lot going on there! We can see that when we create the list that, despite passing in 'datagy', that it’s not included in the list.

Let’s break down some of the more foundational concepts by looking at the individual code blocks.

# Understanding the __init__() Function
from collections import UserList

class NumberList(UserList):
    def __init__(self, iterable):
        super().__init__(
            item for item in iterable if type(item) in [int, float])

In the __init__() method, we overwrite the creation of a list. This happens when we call the super().__init__() method, which allows us to customize how a list is created. In this case, we loop over each item and keep only the integers or floats. To learn more about how this iterating works, check out this guide on list comprehensions.

# Overwriting the __setitem__ Method
from collections import UserList

class NumberList(UserList):
    ...

    def __setitem__(self, index, item):
        if type(item) in [int, float]:
            self.data[index] = item
        else:
            raise TypeError('Item must be a number.')

We overwrite the method that sets items by checking whether the item is either a float or an integer. If it is, it uses the .data attribute to directly assign a value to the underlying list at the index position. If it’s not, the method raises a TypeError indicating that the value must be a number.

# Overwriting the .append() Method
from collections import UserList

class NumberList(UserList):
    ...
    def append(self, item):
        if type(item) in [int, float]:
            self.data.append(item)
        else:
            raise TypeError('Item must be a number.')

In this code block, we overwrite the .append() method in a similar fashion to the __setitem__() method. What’s interesting in this block is that we can use the underlying .append() list method to add an item to the end of a list.

# Adding a Custom List Method
from collections import UserList

class NumberList(UserList):
    ...
    def square_values(self):
        for item in self.data:
            print(item ** 2)

In the code block above, we create a method that simply prints the square of every single value in the list. We do this by using a for loop that accesses each item in the .data attribute. The loop then iterates over each item and prints the square of it.

Let’s see how we can call this method:

# Squaring All Values in Our List
custom_list = NumberList([1, 2, 3, 'datagy'])
custom_list.square_values()

# Returns:
# 1
# 4
# 9

The method above is mostly for illustrative purposes – it doesn’t really accomplish anything you’d normally do.

Conclusion

In this tutorial, you learned how to use the UserList class from the Python collections module to create custom Python lists. You can easily build new lists that have custom behavior or new functionalities, which build on top of regular Python lists.

In this tutorial, you learned how to use the Python collections UserList class to create custom lists. You also learned how to follow through with an example of how to create a custom UserList, by creating a list that only accepts numbers as input and gives you the option to square all values with a custom method.

Additional Resources

To learn more about related topics, check out the tutorials below:

Nik Piepenbreier

Nik is the author of datagy.io and has over a decade of experience working with data analytics, data science, and Python. He specializes in teaching developers how to use Python for data science using hands-on tutorials.View Author posts

Leave a Reply

Your email address will not be published. Required fields are marked *