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:

  1. 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 TypeError on instantiation, preventing bugs.

  2. 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. Iterable requires __iter__, Container requires __contains__, and Sized requires __len__.

  • Sequence, Mapping, Set: The immutable collection types. Sequence is for ordered, indexed collections. Mapping is for key-value pairs.

  • MutableSequence, MutableMapping, MutableSet: The mutable versions of the above.

Building a Custom Sequence: UniqueSequence

Let'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