Chapter 7: Emulating Container Types with collections.abc
Python's built-in container types—list, tuple, dict, set—are incredibly powerful, but sometimes you need a container with specialized behavior. You might want a list that only accepts certain types, a dictionary with a fixed set of keys, or a sequence that maintains a unique set of ordered items.
In Chapter 1, we made our FrenchDeck behave like a sequence by implementing __len__ and __getitem__. While this works, it's an informal approach. For creating robust, full-featured container types, the modern and correct approach is to inherit from the Abstract Base Classes (ABCs) found in the collections.abc module.
Using these ABCs provides two major advantages:
Clear Interface Definition: The ABCs force you to implement all the necessary methods for a given container type. If you forget one, Python will raise a
TypeErroron instantiation, preventing bugs.Free Functionality: By implementing the required abstract methods, your custom class gets a rich set of concrete methods for free, thanks to the mixin methods provided by the ABC.
This chapter will demonstrate how to build a custom mutable sequence by inheriting from collections.abc.MutableSequence.
Abstract Base Classes for Collections
The collections.abc module provides a hierarchy of ABCs for various collection types. Some of the most important are:
Iterable,Container,Sized: The most basic ABCs.Iterablerequires__iter__,Containerrequires__contains__, andSizedrequires__len__.Sequence,Mapping,Set: The immutable collection types.Sequenceis for ordered, indexed collections.Mappingis for key-value pairs.MutableSequence,MutableMapping,MutableSet: The mutable versions of the above.
Building a Custom Sequence: UniqueSequence
UniqueSequenceLet's build a UniqueSequence, a class that behaves like a list but does not allow duplicate items. By inheriting from collections.abc.MutableSequence, we only need to implement a handful of abstract methods to get the full functionality of a list.
The abstract methods required for MutableSequence are:
__getitem____setitem____delitem____len__insert
The "Free" Methods
Now, even though we only implemented five core methods, our UniqueSequence class can do much more. The mixin methods from MutableSequence are automatically available.
Methods like append, extend, pop, reverse, __contains__, and clear are all inherited from the MutableSequence ABC. They are implemented in terms of the five abstract methods we provided. This saves an enormous amount of work and ensures that our custom container behaves consistently and correctly.
Summary
When you need to create a custom container, inheriting from the collections.abc module is the definitive, Pythonic approach. It provides a formal contract that your class must adhere to, catching errors early and ensuring a complete implementation. In return for implementing a small set of core methods, you receive a wealth of additional functionality for free, making your custom container a well-behaved and fully-featured citizen of the Python ecosystem.
Last updated