Python UserList: Custom Sequences

Published on: August 30, 2026
Reading time: 2 minutes
Close-up of vibrant JavaScript code featuring functions and syntax highlighting.

collections.UserList is a helper class for building custom mutable sequences. It stores elements in a regular list exposed through data and offers a predictable extension surface for validation, normalization, logging, and domain rules.

It is useful when a collection should behave like a list but must control insertions, replacements, deletion, accepted types, or batch operations.

Basic example

from collections import UserList

class IntegerList(UserList):
    def _validate(self, value):
        if not isinstance(value, int):
            raise TypeError("integers only")
        return value

    def append(self, value):
        super().append(self._validate(value))

    def insert(self, index, value):
        super().insert(index, self._validate(value))

Validating only append is not enough. A list can also change through index assignment, slices, extend, and +=.

Covering mutation paths

class IntegerList(UserList):
    def _validate(self, value):
        if not isinstance(value, int):
            raise TypeError("integers only")
        return value

    def __setitem__(self, index, value):
        if isinstance(index, slice):
            value = [self._validate(item) for item in value]
        else:
            value = self._validate(value)
        super().__setitem__(index, value)

    def append(self, value):
        super().append(self._validate(value))

    def insert(self, index, value):
        super().insert(index, self._validate(value))

    def extend(self, values):
        super().extend(self._validate(item) for item in values)

The data attribute

data contains the actual list. Direct changes can bypass validation, so treat it as an implementation detail.

Normalizing values

class Tags(UserList):
    def _normalize(self, value):
        text = str(value).strip().casefold()
        if not text:
            raise ValueError("empty tag")
        return text

Decide whether duplicates are valid. If uniqueness is the main rule, a set or mapping may model the domain better.

UserList versus list subclassing

A direct list subclass may be faster and can be required by APIs expecting the concrete type. UserList prioritizes extensibility and routes operations through methods that are easier to customize.

UserList versus MutableSequence

Implement MutableSequence when storage is not an ordinary list, such as disk-backed data, a virtual window, or a compact structure. Choose UserList when an internal list is sufficient.

Operations returning new sequences

Test concatenation, multiplication, slicing, and copying. Define whether results should preserve the custom class or become normal lists.

Sorting and instrumentation

class Tasks(UserList):
    def sort(self, *, key=None, reverse=False):
        log("sorting tasks")
        super().sort(key=key, reverse=reverse)

Avoid expensive or surprising side effects in familiar list operations.

Serialization

Some serializers require a concrete list. Convert explicitly:

import json
json.dumps(list(values))

Common mistakes

  • Validating only append.
  • Ignoring slice assignment and extend.
  • Changing data directly.
  • Using a list when uniqueness is required.
  • Assuming the result type of slicing or concatenation.

Inventory every mutation path, centralize validation, call super(), test operators, and document result types. See the internal guides to Python lists and collections.

Conclusion

UserList is a practical base for custom sequences backed by a regular list. It helps enforce consistent invariants without depending on list implementation details.

External sources

Share:

Facebook
WhatsApp
Twitter
LinkedIn

Article content

    Related articles

    A laptop screen showing a code editor with visible programming code in a dimly lit environment.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python UserDict: Custom Mappings

    Learn Python UserDict for custom mappings with validation, normalization, composition, copying, and predictable mutation behavior.

    Ler mais

    Tempo de leitura: 2 minutos
    30/08/2026
    Detailed close-up of yellow and white albino python scales, capturing texture and pattern.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    itertools.accumulate: Running Sums and State

    Learn Python itertools.accumulate for running sums, balances, records, custom state transitions, and lazy data pipelines.

    Ler mais

    Tempo de leitura: 2 minutos
    30/08/2026
    A developer typing code on a laptop with a Python book beside in an office.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    itertools.groupby: Group Sorted Data Correctly

    Learn Python itertools.groupby for ordered data, streaming aggregation, shared iterators, object keys, and correct grouping behavior.

    Ler mais

    Tempo de leitura: 2 minutos
    30/08/2026
    Close-up of hands typing on a laptop keyboard, Python book in sight, coding in progress.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    contextlib.chdir: Risks of Changing Directories

    Learn Python contextlib.chdir, its global-state and concurrency risks, and when pathlib or subprocess cwd is the safer design.

    Ler mais

    Tempo de leitura: 3 minutos
    30/08/2026
    A person typing on a laptop with a Python programming book visible, capturing technology and learning.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    Python nullcontext: Optional Contexts

    Use Python nullcontext to unify optional files, locks, transactions, sessions, and borrowed resources without duplicate branches.

    Ler mais

    Tempo de leitura: 4 minutos
    30/08/2026
    Detailed shot of a Jungle Carpet Python (Morelia spilota cheynei) in its natural habitat.
    Advanced Python
    Foto de perfil de Leandro Hirt da Academify

    contextlib.aclosing: Close Async Generators Safely

    Learn Python contextlib.aclosing to close async generators safely after break, return, exceptions, cancellation, and partial consumption.

    Ler mais

    Tempo de leitura: 5 minutos
    30/08/2026