ZetCode

Python __delitem__ 方法

最后修改于 2025 年 4 月 8 日

本综合指南探讨了 Python 的 __delitem__ 方法,该特殊方法负责容器对象中的项目删除。我们将介绍基本用法、字典操作、列表操作和自定义实现。

基本定义

__delitem__ 方法被调用以使用 del 语句或类似操作来实现项目的删除。它允许对象定义在通过键或索引删除项目时的自定义行为。

主要特征:它接受实例 (self) 和键/索引作为参数,就地修改对象,并且通常返回 None。它由 del obj[key] 语法调用。

基本的 __delitem__ 实现

这是一个简单的实现,展示了 __delitem__ 在自定义容器类中的工作方式。 这演示了基本结构和用法。

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}

此示例显示了一个包装字典的容器。 当我们在项目上使用 del 时,它会调用 __delitem__,然后从内部字典中删除。

该方法接收删除操作中使用的键,并执行从容器存储中进行的实际删除。 不需要返回值。

实现类似列表的删除

对于支持基于索引删除的序列类型,__delitem__ 可以处理整数和切片,类似于内置列表。

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])

这个类似列表的类处理单个索引删除和切片删除。 该方法检查索引参数的类型以正确处理这两种情况。

切片处理与 Python 的内置列表行为相同,使该类的行为类似于标准序列类型。

具有删除日志记录的字典子类

我们可以创建一个字典子类,通过覆盖 __delitem__ 来记录所有删除操作,同时保持所有字典行为。

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

这个字典子类在执行实际删除之前添加日志记录。 它使用 super() 来调用父类的 __delitem__

这种模式对于调试或跟踪类似字典的对象中的更改非常有用,而无需更改其核心功能。

具有删除约束的自定义容器

__delitem__ 可以强制执行对可以删除哪些项目的约束,例如防止删除某些受保护的键。

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}}

此容器通过在允许操作之前检查一组受保护的键来保护某些键免于删除。 它为受保护的项目引发 KeyError

当您需要维护某些内部状态,同时允许修改容器的其他部分时,此模式非常有用。

具有行/列删除的矩阵类

对于更复杂的数据结构,__delitem__ 可以实现复杂的删除逻辑,例如从矩阵中删除整行或整列。

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)

此矩阵类处理两种类型的删除:删除整行(按整数索引)或将单个元素置零(按 (行,列) 元组)。 该方法检查键类型以确定操作。

这演示了 __delitem__ 如何在单个类中支持多种删除语义,从而提供灵活的容器行为。

最佳实践

资料来源

作者

我的名字是 Jan Bodnar,我是一位充满热情的程序员,拥有丰富的编程经验。 我自 2007 年以来一直在撰写编程文章。 迄今为止,我已经撰写了 1,400 多篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 Python 教程