Complete guide to Python's __delitem__ method covering dictionary operations, list operations, and custom container implementations.
Last modified April 8, 2025
This comprehensive guide explores Python’s delitem method, the special method responsible for item deletion in container objects. We’ll cover basic usage, dictionary operations, list operations, and custom implementations.
The delitem method is called to implement deletion of items using the del statement or similar operations. It allows objects to define custom behavior when items are deleted by key or index.
Key characteristics: it takes the instance (self) and key/index as arguments, modifies the object in-place, and typically returns None. It’s invoked by del obj[key] syntax.
Here’s a simple implementation showing how delitem works in a custom container class. This demonstrates the basic structure and usage.
basic_delitem.py
class MyContainer: def init(self): self.data = {‘a’: 1, ‘b’: 2, ‘c’: 3}
def __delitem__(self, key):
print(f"Deleting item with key: {key}")
del self.data[key]
container = MyContainer() del container[‘b’] # Calls delitem print(container.data) # {‘a’: 1, ‘c’: 3}
This example shows a container that wraps a dictionary. When we use del on an item, it calls delitem which then deletes from the internal dictionary.
The method receives the key used in the deletion operation and performs the actual removal from the container’s storage. No return value is needed.
For sequence types that support index-based deletion, delitem can handle both integers and slices, similar to built-in lists.
list_delitem.py
class MyList: def init(self, items): self.items = list(items)
def __delitem__(self, index):
if isinstance(index, slice):
del self.items[index]
else:
del self.items[index]
def __repr__(self):
return f"MyList({self.items})"
lst = MyList([10, 20, 30, 40, 50]) del lst[1] # Delete single item print(lst) # MyList([10, 30, 40, 50]) del lst[1:3] # Delete slice print(lst) # MyList([10, 50])
This list-like class handles both single index deletion and slice deletion. The method checks the type of the index parameter to handle both cases properly.
The slice handling is identical to Python’s built-in list behavior, making the class behave like a standard sequence type.
We can create a dictionary subclass that logs all deletion operations by overriding delitem while maintaining all dictionary behavior.
logging_dict.py
class LoggingDict(dict): def delitem(self, key): print(f"Log: Deleting key ‘{key}’") super().delitem(key)
d = LoggingDict({‘red’: ‘#FF0000’, ‘green’: ‘#00FF00’, ‘blue’: ‘#0000FF’}) del d[‘green’] # Logs the deletion print(d) # {‘red’: ‘#FF0000’, ‘blue’: ‘#0000FF’}
This dictionary subclass adds logging before performing the actual deletion. It uses super() to call the parent class’s delitem.
This pattern is useful for debugging or tracking changes in dictionary-like objects without changing their core functionality.
delitem can enforce constraints on what items can be deleted, such as preventing deletion of certain protected keys.
protected_container.py
class ProtectedContainer: def init(self): self._data = {‘config’: {}, ‘values’: {}} self._protected = {‘config’}
def __delitem__(self, key):
if key in self._protected:
raise KeyError(f"Cannot delete protected key: {key}")
del self._data[key]
def __repr__(self):
return str(self._data)
pc = ProtectedContainer() pc._data[‘config’][’timeout’] = 30 pc._data[‘values’][’temp’] = 98.6
try: del pc[‘config’] # Raises KeyError except KeyError as e: print(e)
del pc[‘values’] # Works print(pc) # {‘config’: {’timeout’: 30}}
This container protects certain keys from deletion by checking against a set of protected keys before allowing the operation. It raises KeyError for protected items.
This pattern is useful when you need to maintain certain internal state while allowing modification of other parts of the container.
For more complex data structures, delitem can implement sophisticated deletion logic, like removing entire rows or columns from a matrix.
matrix_deletion.py
class Matrix: def init(self, rows, cols): self.rows = [[0] * cols for _ in range(rows)] self.row_count = rows self.col_count = cols
def __delitem__(self, key):
if isinstance(key, tuple) and len(key) == 2:
row, col = key
self.rows[row][col] = 0
elif isinstance(key, int):
del self.rows[key]
self.row_count -= 1
else:
raise TypeError("Invalid key type")
def __repr__(self):
return '\n'.join(' '.join(map(str, row)) for row in self.rows)
m = Matrix(3, 3) m.rows = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] print(“Original matrix:”) print(m)
del m[1] # Delete entire row print("\nAfter deleting row 1:") print(m)
del m[0, 1] # Delete single element (set to 0) print("\nAfter deleting element at (0,1):") print(m)
This matrix class handles two types of deletion: removing entire rows (by integer index) or zeroing out individual elements (by (row,col) tuple). The method checks the key type to determine the operation.
This demonstrates how delitem can support multiple deletion semantics in a single class, providing flexible container behavior.
Maintain consistency: Ensure deletion leaves the object in a valid state
Handle errors: Raise appropriate exceptions for invalid keys
Document behavior: Clearly specify what deletion operations are supported
Consider performance: Some deletion operations may be expensive
Support slicing: For sequence types, handle slice objects
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.
List all Python tutorials.