如何在Python中扩展List类以支持整数/布尔列表式索引
扩展Python List类支持整数/布尔列表索引
你说得太对了!Python里的方括号[]操作,底层就是调用__getitem__(读取)和__setitem__(赋值)这两个特殊方法,继承list类后重写它们,完全是实现你需求的正确方向。咱们一步步来看你的实现过程和优化点:
最初代码的问题
你一开始写的版本有两个关键bug:
__getitem__里的循环直接return self[i],会在第一次循环就返回结果,只能拿到第一个索引对应的元素,而不是所有索引的集合__setitem__的else分支里写错了变量,应该是list.__setitem__(self, index, item),而不是self[i] = item(这里的i是循环里的变量,else分支里根本不存在)
第一步:修复__getitem__实现
你后来修改的__getitem__思路很正确:调用父类的list.__getitem__来避免递归调用自己的方法,然后遍历索引列表收集所有结果返回,这样就能正常获取多个索引对应的元素了:
def __getitem__(self, index): if type(index) is list: res = [None]*len(index) for i,v in enumerate(index): res[i] = list.__getitem__(self, v) return res else: return list.__getitem__(self, index)
第二步:修复__setitem__实现
同样的,你修改后的__setitem__通过循环遍历索引和值的配对,调用父类方法逐个赋值,这就解决了批量赋值的问题:
def __setitem__(self, index, value): if type(index) is list: for i,v in zip(index, value): list.__setitem__(self,i,v) else: list.__setitem__(self,index,value)
第三步:添加布尔列表索引支持
你把布尔列表转换成对应的整数索引的思路非常巧妙——先筛选出True对应的位置索引,然后复用已有的整数列表索引逻辑,这样不用重复写赋值/读取的代码。不过这里可以提个小优化:用isinstance()代替type()会更灵活,比如能兼容布尔值的子类(虽然实际场景很少,但更符合Python的鸭子类型思想)。
最终完整实现
class MyList(list): def __getitem__(self, index): if isinstance(index, list): if index and isinstance(index[0], bool): # 把布尔列表转换为整数索引列表 int_indices = [i for i, val in enumerate(index) if val] return self[int_indices] elif index and isinstance(index[0], int): res = [] for idx in index: res.append(list.__getitem__(self, idx)) return res # 其他情况调用父类方法 return list.__getitem__(self, index) def __setitem__(self, index, value): if isinstance(index, list): if index and isinstance(index[0], bool): # 布尔列表转整数索引后复用逻辑 int_indices = [i for i, val in enumerate(index) if val] self[int_indices] = value elif index and isinstance(index[0], int): for idx, val in zip(index, value): list.__setitem__(self, idx, val) # 其他情况调用父类方法 list.__setitem__(self, index, value)
测试验证
咱们用你给出的测试案例验证一下:
# 测试整数列表索引 list1 = MyList(['a','b','c','d','e']) list2 = MyList(['A','B','C','D','E']) index1 = [0,1,3] index2 = [1,2,4] list1[index1] = list2[index2] print(list1) # 输出: ['B', 'C', 'c', 'E', 'e'] # 测试布尔列表索引 list1 = MyList(['a','b','c','d','e']) index_bool1 = [True,True,False,True,False] index_bool2 = [False,True,True,False,True] list1[index_bool1] = list2[index_bool2] print(list1) # 输出: ['B', 'C', 'c', 'E', 'e']
完全符合你的预期结果!
额外小提示
- 处理布尔列表时,要确保布尔列表的长度和原列表一致,否则会出现索引越界的问题
- 用
isinstance(index, list)比type(index) is list更健壮,因为它能识别继承自list的子类对象
内容的提问来源于stack exchange,提问作者Confounded
相关产品推荐
相关产品推荐

