Skip to content

Container Emulation

One of the most powerful aspects of Python is its “Plug-and-Play” nature. You don’t have to inherit from a special List class to make your object behave like a list. By implementing a handful of “Magic Methods,” your custom object can support indexing, slicing, iteration, and the in operator.

This is known as the Container Protocol.


1. The Core Three: Length, Getting, and Setting

Section titled “1. The Core Three: Length, Getting, and Setting”

Called when you run len(obj). Should return an integer.

Called when you run obj[key].

  • For a Sequence (list-like), the key is an integer or a slice.
  • For a Mapping (dict-like), the key is an immutable object.

Called when you run obj[key] = value.

simple_container.py
class Box:
def __init__(self):
self._items = {}
def __len__(self):
return len(self._items)
def __getitem__(self, key):
return self._items.get(key, "Empty")
def __setitem__(self, key, value):
self._items[key] = value
b = Box()
b["tool"] = "Hammer"
print(b["tool"]) # Hammer
print(len(b)) # 1

Called when you use the in operator.

if "Hammer" in b: # Calls b.__contains__("Hammer")
...

Called when you use a for loop. It should return an Iterator object.


To support slicing (obj[1:5]), you don’t need a new method. Python passes a slice object into your __getitem__ method instead of an integer.

slicing_support.py
class CustomList:
def __init__(self, data):
self.data = data
def __getitem__(self, index):
if isinstance(index, slice):
print(f"Slicing from {index.start} to {index.stop}")
return self.data[index]
return self.data[index]
c = CustomList([10, 20, 30, 40])
print(c[1:3]) # Output: [20, 30]

4. Under the Hood: The “Collection” Abstract Base Classes

Section titled “4. Under the Hood: The “Collection” Abstract Base Classes”

If you are building a production-grade container, you shouldn’t just guess which methods to implement. Python provides Abstract Base Classes in the collections.abc module (like Sequence, MutableSequence, Mapping).

By inheriting from these, you get many methods (like __contains__, __iter__, and __reversed__) for free, provided you implement the core ones (__getitem__ and __len__).


OperationMagic Method
len(obj)__len__
obj[k]__getitem__
obj[k] = v__setitem__
del obj[k]__delitem__
item in obj__contains__
for x in obj__iter__
reversed(obj)__reversed__