[Python] Implement your own list-like class using collections.UserList

When I was researching python's collections, there was almost no article about collections.UserList, so I tried to summarize how to use it.

What is collections.UserList?

The Official Documentation says:

This class acts as a wrapper for list objects. This is useful as a base class for your own list-like class, where you can override existing methods or add new ones. This way you can add new behavior to the list.

As mentioned above, ʻUserList is the base class for creating your own list-like class. A list-like class is a class that can create ʻappend and remove, and has an indexer.

Try using collections.UserList

As an example, let's implement a list ResettableList with areset method that returns the list to its initial state at the time of the constructor.

python


from collections import UserList


# collections.Inherit UserList
class ResettableList(UserList):
    def __init__(self, initlist=None):
        super().__init__(initlist)
        self._initlist = initlist.copy()  #Keep a copy of the initlist

    def reset(self):
        self.data = self._initlist.copy()  # self.data is the wrapped list


mylist = ResettableList([1, 2, 3])  #Pass the initial list to the constructor
print(f'mylist = {mylist}')
print(f'mylist.data = {mylist.data}')  # [not recommended]You can access the internal list with data

#You can operate like a normal list
print(f'mylist[1] = {mylist[1]}')
mylist.append(4)
print(f'mylist = {mylist}')
mylist.remove(1)
print(f'mylist = {mylist}')

mylist.reset()  #Return to the initial state
print(f'mylist = {mylist}')

result

mylist = [1, 2, 3]
mylist.data = [1, 2, 3]
mylist[1] = 2
mylist = [1, 2, 3, 4]
mylist = [2, 3, 4]
mylist = [1, 2, 3]

ResettableList is a wrapper and stores the list in the member variable data. The reset method, which has its own behavior, is implemented by manipulating this self.data. Also, in the example, the member variable data is accessed from the outside, but this behavior should be avoided because it may cause unexpected problems.

To show this, we have implemented a list ʻUnremovableList` that cannot remove elements.

python


from collections import UserList


#Exception when a method that deletes an element is used
class RemoveError(Exception):
    pass


class UnremovableList(UserList):
    #Override the method that deletes the element and raise an exception
    #For simplicity, only remove is overridden here
    def remove(self, item):
        raise RemoveError('Cannot remove')


mylist = UnremovableList([1, 2, 3])
print(f'mylist = {mylist}')

#Cannot be removed
try:
    mylist.remove(1)
except RemoveError as e:
    print(f'RemoveError: {e}')
print(f'mylist = {mylist}')

# mylist.I can remove it when I access data
mylist.data.remove(1)
print(f'mylist = {mylist}')

result

mylist = [1, 2, 3]
RemoveError: Cannot remove
mylist = [1, 2, 3]
mylist = [2, 3]

By accessing data from the outside in this way, you can delete the elements that should have been prohibited.

It's okay to inherit list

If you want to create a list-like class, you should be able to inherit list. Is there a merit to inherit collections.UserList instead of list? The Official Document states as follows.

The need for this class has been partially superseded by the ability to subclass directly from list; however, it's easier to use this class because it gives you access to the underlying list as an attribute. There is also.

"This class" is ʻUserList. In summary, "You may inherit list, but it's easier to inherit ʻUserList."

Let's see what the implementation would look like if we inherited list. Implement the ResettableList from the previous example this way.

python


class ResettableList(list):
    def __init__(self, initlist=None):
        super().__init__(initlist)
        self._initlist = initlist.copy()

    def reset(self):
        self.clear()
        self.extend(self._initlist)

You have to work with your own instance, unlike when you inherited ʻUserList`. Therefore, I implemented it by emptying the list once and adding the initial list.

A comparison of the two is as follows. (Only the reset method is described)

python


#UserList inherited version
class ResettableList(UserList):
    def reset(self):
        self.data = self._initlist.copy()


#list inherited version
class ResettableList(list):
    def reset(self):
        self.clear()
        self.extend(self._initlist)

It is simpler to inherit ʻUserList`.

in conclusion

So far, I have summarized how to use collections.UserList in my own way. ʻUserList` has a structure that has a list inside, but looks like the list itself when viewed from the outside. I think this will also be helpful when extending common classes.

By the way, collections also has ʻUserDict and ʻUserString, which are similar to ʻUserList. It is a base class for creating dict and str`-like classes, respectively. I don't think I use these classes very often, but I would like to use them appropriately in these situations.

Recommended Posts

[Python] Implement your own list-like class using collections.UserList
python: Use your own class for numpy ndarray
[Road to intermediate Python] Define in in your own class
[Python] Make your own LINE bot
[Python] logging in your own module
Create your own graph structure class and its drawing in python
Call your own C language shared library from Python using ctypes
Specify your own class in class argument and return type annotation in Python
Create your own Linux commands in Python
Implement __eq__ etc. generically in Python class
[LLDB] Create your own command in Python
Easily use your own functions in Python
[Python] Package and distribute your own modules
Tweet your own sentences using Markov chains
[Python] Register your own library on PyPI
Until you install your own Python library
[python] How to add RDF triples to your own Fuseki server using rdflib
Publish your own Python library with Homebrew
How to access data with object ['key'] for your own Python class
Get your own IP address in Python
Email attachments using your gmail account in python.
Make your own module quickly with setuptools (python)
Import your own modules in Grasshopper's Python development
[Python] class, instance
"Kanrika" python class
About python, class
Start using Python
Python class, instance
Scraping using Python
#Python basics (class)
Flow of creating your own package with setup.py with python
Memo to create your own Box with Pepper's Python
Call your own C library with Go using cgo
Create your own Big Data in Python for validation
[Introduction to Udemy Python 3 + Application] 66. Creating your own exceptions
Take your own peak memory usage on Linux & Python
Create your own Random Dot Stereogram (RDS) in Python.
Try to improve your own intro quiz in Python
Let's call your own C ++ library with Python (Preferences)
[Blender × Python] Create your own function & summary so far
Use the CASA Toolkit in your own Python environment
Build a Python environment on your Mac using pyenv
Create your first GDSII file in Python using gdspy
Call your own python module from the ROS package