Python __delitem__() 方法

Python __delitem__() 语法

__delitem__() 是 Python 的一个特殊方法(又称 “魔法方法” 或 “双下划线方法”),它用于定义当使用 del 语句删除对象的元素时(如 del obj[key]),其行为是怎么样的。

__delitem__() 方法可以使得自定义对象能够像序列(列表)或映射(字典)一样支持 “索引删除” 或 “切片删除” 。

语法:

class MyObject:
    def __delitem__(self, key):
        # 根据 key 删除对应的元素。key 可以是索引、切片对象或哈希键
        del self.data[key]

说明:

__delitem__() 方法接收以下 3 个参数。

  • self(必选) :约定俗成的名称,代表实例对象。
  • key(必选) :表示用于删除元素的键,它的类型取决于删除方式:
    • 如果是 del obj[index],key 应该是一个整数。
    • 如果是 del obj['name'],key 应该是一个字符串。
    • __delitem__() 不支持切片删除(del obj[start:stop:step])。如果你需要支持切片删除,通常需要在 __delitem__() 内部自行解析 slice 对象。然而,Python 的 del 语句默认对 slice 对象不直接调用 __delitem__()。通常我们会为可变序列实现 __delitem__() 对整数索引和 slice 对象进行处理。

__delitem__() 方法不返回任何值(隐式返回 None)。如果 key 无效(比如键不存在或索引越界),应抛出相应的异常(如 IndexError、KeyError 或 TypeError)。

提示:如果一个类实现了 __delitem__() 方法,那么它的实例就支持使用 del obj[key] 操作符进行元素删除和切片删除。

Python __delitem__() 摘要

属于 Python 魔法方法
使用频率
官方文档 查看
相关方法 __getitem__()__setitem__()

Python __delitem__() 示例

接下来,我们通过几个简单的例子来讲解一下 Python __delitem__() 方法是如何使用的。

示例 1:__delitem__() 实现索引删除

class MySequence:
    def __init__(self, data):
        self._items = list(data)

    def __getitem__(self, index):
        return self._items[index]

    def __setitem__(self, index, value):
        self._items[index] = value

    def __delitem__(self, index):
        # 实现通过索引删除元素
        if not isinstance(index, int):
            raise TypeError('索引必须是整数')
        if not (0 <= index < len(self._items)):
            raise IndexError('索引已超出范围')
        del self._items[index]

    def __len__(self):
        return len(self._items)

    def __repr__(self):
        return f'MySequence({self._items})'

# 创建实例
seq = MySequence(['red', 'green', 'blue', 'yellow'])
print(seq)

# 通过索引删除元素
del seq[1]
print(seq)

# 尝试删除不存在的索引
try:
    del seq[5]
except IndexError as e:
    print(e)

# 尝试使用非整数索引
try:
    del seq['key']
except TypeError as e:
    print(e)

运行结果如下。

MySequence(['red', 'green', 'blue', 'yellow'])
MySequence(['red', 'blue', 'yellow'])
索引已超出范围
索引必须是整数

分析:

在 MyList 类中,我们手动实现了 __delitem__() 方法。该方法使得其实例能够像普通列表一样使用 del obj[index] 语法删除元素。

当 del seq[1] 被执行时,__delitem__() 方法被触发,然后接收 “1” 作为 index 参数,并从内部列表中删除对应位置的元素。

示例 2:__delitem__() 实现切片删除

class MySequence:
    def __init__(self, data):
        self._items = list(data)

    def __getitem__(self, key):
        return self._items[key]

    def __setitem__(self, key, value):
        if isinstance(key, slice):
            self._items[key] = list(value)
        else:
            self._items[key] = value

    def __delitem__(self, key):
        # 实现通过索引或切片删除元素
        if isinstance(key, slice):
            del self._items[key]
        elif isinstance(key, int):
            del self._items[key]
        else:
            raise TypeError(f'不支持的键类型: {type(key)}')

    def __len__(self):
        return len(self._items)

    def __repr__(self):
        return f'MySequence({self._items})'

seq = MySequence([10, 20, 30, 40, 50, 60, 70])
print(seq)

# 切片删除 (删除连续部分)
del seq[1:3]
print(seq)

# 切片删除 (删除步长部分)
del seq[::2]     # 注意:经过上一步,seq已经变成 [10, 40, 50, 60, 70]
print(seq)

# 尝试删除空切片(不报错,但也没啥效果)
del seq[10:12]
print(seq)

运行结果如下。

MySequence([10, 20, 30, 40, 50, 60, 70])
MySequence([10, 40, 50, 60, 70])
MySequence([40, 60])
MySequence([40, 60])

分析:

__delitem__() 同样处理切片对象,从而实现切片删除功能。在这个例子中,当使用切片删除语法(如 del seq[1:3])时,Python 会将切片表达式转换为一个 slice 对象,并将其作为 key 参数传递给 __delitem__()。我们可以在 __delitem__() 内部检查 key 的类型来分别处理索引和切片删除。

需要注意的是,切片删除会改变原列表的长度和索引,因此后续的删除操作需要考虑这一点。

示例 3:__delitem__() 实现字典风格的键删除

class UserPreferences:
    def __init__(self, prefs=None):
        self._prefs = prefs if prefs is not None else {}

    def __getitem__(self, key):
        return self._prefs[key]

    def __setitem__(self, key, value):
        self._prefs[key] = value

    def __delitem__(self, key):
        # 实现通过键删除配置项
        if not isinstance(key, str):
            raise TypeError('键必须是字符串')
        if key not in self._prefs:
            raise KeyError(f'找不到 {key} 键')
        del self._prefs[key]

    def __len__(self):
        return len(self._prefs)

    def __repr__(self):
        return f'UserPreferences({self._prefs})'

prefs = UserPreferences({
    'theme': 'dark',
    'notifications': True,
    'language': 'zh-CN'
})
print(prefs)

# 删除一个偏好设置
del prefs['notifications']
print(prefs)

# 添加一个新设置
prefs['font_size'] = 14
print(prefs)

# 尝试删除不存在的键
try:
    del prefs['invalid_key']
except KeyError as e:
    print(e)

# 尝试使用非字符串键删除
try:
    del prefs[123]
except TypeError as e:
    print(e)

运行结果如下。

UserPreferences({'theme': 'dark', 'notifications': True, 'language': 'zh-CN'})
UserPreferences({'theme': 'dark', 'language': 'zh-CN'})
UserPreferences({'theme': 'dark', 'language': 'zh-CN', 'font_size': 14})
(报错)'找不到 invalid_key 键'
(报错)键必须是字符串

分析:

__delitem__() 也可以用于实现字典风格的键删除。在这个例子中,当 del user_prefs['notifications'] 被执行时,__delitem__() 会被调用,并接收 'notifications' 作为 key,然后从内部字典 _prefs 中删除对应的键值对。

示例 4:对不支持删除操作的对象进行 del

class MyObject:
    def __init__(self, data):
        self._data = tuple(data)     # 内部使用元组,使其不可变

    def __getitem__(self, index):
        return self._data[index]

    def __len__(self):
        return len(self._data)

    def __repr__(self):
        return f'MyObject{self._data}'

obj = MyObject(['a', 'b', 'c'])
print(obj)

# 尝试对只读对象进行删除操作
try:
    del obj[0]
except TypeError as e:
    print(e)

try:
    del obj[1:2]
except TypeError as e:
    print(e)

运行结果如下。

MyObject('a', 'b', 'c')
'MyObject' object doesn't support item deletion
'MyObject' object does not support item deletion

分析:

如果一个自定义对象在设计上不支持删除元素,但我们尝试对它进行删除操作,Python 就会抛出 TypeError 异常。

上一篇: __setitem__()

下一篇: __iter__()

给站长反馈

绿叶网正在不断完善中,小伙伴们如果发现任何问题,还望多多给站长反馈,谢谢!

邮箱:lvyenet@vip.qq.com

「绿叶网」服务号
绿叶网服务号放大
关注服务号,微信也能看教程。
绿叶网服务号