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 异常。
