UserDict, UserList, UserString

Subclassing dict directly has a catch: its C methods (update, the constructor, get …) do not call your __setitem__ or __getitem__. UserDict is written in Python on top of .data, so overriding one method changes them all.

collections classesPython 3.0+
Common call
class LowerDict(UserDict): …
Returns
a dict-like object backed by self.data
Replaces
subclassing dict / list / str when overrides must apply everywhere
Watch out
isinstance(UserDict(), dict) is False
collections.UserDict([initialdata])
→ UserDict | UserList | UserString

Parameters

NameTypeRequiredDescription
initialdatamapping | iterablenoUserDict: initial contents (copied into a new dict in .data). Keyword arguments work too.
listiterablenoUserList: initial items (copied into .data).
seqobjectyesUserString: converted with str() into .data.

Return value

UserDict | UserList | UserString — An object that stores its contents in the .data attribute (a dict, list or str).

Attributes

AttributeTypeMeaning
datadict | list | strThe real contents. Methods read and write it; you can too.

Common patterns

A dict that normalises keys
Override __setitem__ once — update() and the constructor use it too.
from collections import UserDict
class LowerDict(UserDict):
    def __setitem__(self, key, value):
        super().__setitem__(key.lower(), value)
A list that validates items
UserList methods such as append go through .data; override the ones you need.
from collections import UserList
class IntList(UserList):
    def append(self, item):
        if not isinstance(item, int):
            raise TypeError("ints only")
        super().append(item)
Reach the raw data
.data is a plain dict / list / str.
plain = my_user_dict.data

Examples

1. Overrides apply to update() too
from collections import UserDict class LowerDict(UserDict): def __setitem__(self, key, value): super().__setitem__(key.lower(), value) d = LowerDict({'A': 1}) d.update(B=2) d.data
Returns
{'a': 1, 'b': 2}
2. A dict subclass skips them
class LowerDict(dict): def __setitem__(self, key, value): super().__setitem__(key.lower(), value) d = LowerDict({'A': 1}) d.update(B=2) d
Returns
{'A': 1, 'B': 2}
3. Not a dict instance
from collections import UserDict isinstance(UserDict(), dict)
Returns
False
4. But a Mapping
from collections import UserDict from collections.abc import MutableMapping isinstance(UserDict(), MutableMapping)
Returns
True
5. UserList keeps a list in .data
from collections import UserList ul = UserList([3, 1, 2]) ul.sort() (ul, type(ul.data).__name__)
Returns
([1, 2, 3], 'list')
6. UserString methods return UserString
from collections import UserString type(UserString('abc').upper()).__name__
Returns
'UserString'

Pitfalls

1. Subclassing dict and overriding __setitem__
dict's own constructor and update() bypass the override, so some keys slip through unnormalised.
class X(dict)
class Upper(dict):
    def __setitem__(self, k, v):
        super().__setitem__(k.upper(), v)
Upper(a=1)
{'a': 1}
class X(UserDict)
from collections import UserDict
class Upper(UserDict):
    def __setitem__(self, k, v):
        super().__setitem__(k.upper(), v)
Upper(a=1).data
{'A': 1}
2. Code that checks isinstance(x, dict)
A UserDict is not a dict. Check against collections.abc.Mapping instead, or pass .data.
isinstance(dict)
from collections import UserDict
isinstance(UserDict(a=1), dict)
False
isinstance(Mapping)
from collections import UserDict
from collections.abc import Mapping
isinstance(UserDict(a=1), Mapping)
True

When to use

Use it
  • Custom containers whose overridden methods must be used consistently
  • Wrapping a dict/list/str with extra behaviour (validation, normalisation, logging)
Reach for something else
  • Only adding new methods (not overriding) → subclass dict/list/str directly and keep isinstance(x, dict)
  • A full custom mapping from scratch → collections.abc.MutableMapping

Notes

CPython impl
Lib/collections/__init__.py — pure Python; UserDict is a MutableMapping, UserList a MutableSequence, UserString a Sequence, each delegating to self.data
No demo
The interesting part is subclassing — class bodies with overrides — which a form input cannot express; the examples show it instead

FAQ

UserDict when you override methods like __setitem__ or __getitem__ and need every other method (update, setdefault, the constructor) to respect them. dict when you only add new methods — you skip the Python-level delegation and pass isinstance(x, dict).