When I was researching python's collections
, there was almost no article about collections.UserList
, so I tried to summarize how to use it.
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.
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.
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`.
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