Python Topics : Custom Collections
Bad Practice? - Subclassing Built-in Types
subclassing built-in types like dict, set, list, and tuple can introduce complications due to
  • method delegation
  • initialization quirks
  • unexpected behavior from internal optimizations
  • potential performance hits
these issues stem from the fact that built-in types are implemented in C
leads to some methods not being overridden as expected or performing sub-optimally when subclassed
Python offers more robust alternatives through composition and the abstract base classes in the collections module
specifically designed for extension and customization without the pitfalls of direct subclassing
The Alternatives
Python provides a number of alternatives in the collections module
for simple dicts and lists there are the UserDict and UserList classes
for Tuples, Sets and more complex list and dict like objects there's a number of abstract mixin classes
allow for creation of customized implementations
provided by the collections.abc module these classes are
  • dict => MutableMapping
  • set => MutableSet
  • list => MutableSequence
  • tuple = does not have a direct mixin alternative
    instead Sequence and Hashable would have to be used
a list of mixin classes can be found at Collections Abstract Base Classes
each of these classes require you to implement a number of methods
by doing so Python will provide the rest of the interface based on these methods
Implementing the Mixins - MutableMapping
to achieve a dict like interface need to implement these methods
class MyMapping(MutableMapping):
    def __getitem__(self, key):
        ...
    def __setitem__(self, key, item):
        ...
    def __delitem__(self, key):
        ...
    def __iter__(self):
        ...
    def __len__(self):
        ...
this will provide the following methods
  • __contains__
  • __eq__
  • __ne__
  • keys
  • items
  • values
  • get
  • popiteem
  • clear
  • update
  • setdefault
Implementing the Mixins - MutableSequence
implement the basic methods and this class will provide a list-like interface.
class MySequence(MutableSequance):
    def __getitem__(self, index):
        ...
    def __setitem__(self, index, item):
        ...
    def __delitem__(self, index):
        ...
    def __iter__(self):
        ...
    def __len__(self):
        ...
    def insert(self, item)
        ...
this will provide the following methods
  • __contains__
  • __iter__
  • __reversed__
  • __iadd__
  • index
  • count
  • append
  • clear
  • reverse
  • extend
  • pop
  • remove
Implementing the Mixins - MutableSet
methods to provide a set like interface
class MySet(MutableSet):
    def __contains__(self, item):
        ...
    def __iter__(self):
        ...
    def __len__(self):
        ...
    def add(self, item):
        ...
    def discard(item):
        ...
this will provide the following methods
  • __le__
  • __lt__
  • __eq__
  • __ne__
  • __gt__
  • __ge__
  • __and__
  • __or__
  • __sub__
  • __xor__
  • __ior__
  • __iand__
  • __ixor__
  • __isub__
  • isdisjoint
  • clear
  • pop
  • remove
Hashable & Sequence
with this class must make use of multiple inheritance to enable the creation of the tuple-like interface
Sequence provides the collection interface but does not provide the Hashable interface
class MyHashableSequance(Hashable, Sequence):
    def __hash__(self):
        ...
    def __getitem__(self, index):
        ...
    def __iter__(self):
        ...
    def __len__(self):
        ...
this will provide the following methods
  • __contains__
  • __iter__
  • __reversed__
  • index
  • count
Conclusions
by implementing a minimal number of methods custom collections can benefit from additional functionality
also have the option to override those methods
classes will align with the same interface as the pre-existing types
enables them to be utilized interchangeably
provides a robust and extensible alternative to extending built-in collections through inheritance
index