如何高效判断自定义__getitem__方法的"key"参数是否为切片?

10 投票
2 回答
4145 浏览
提问于 2025-04-16 17:57

我有一个自定义的序列类型。它基本上是一个列表的包装,加上一个布尔标志,我想让它表现得像通常的不可变序列。

我遇到的问题是关于切片的。我知道在Python 3中,想要实现切片功能,需要有一个叫做 __getitem__(key) 的方法。如果 %key 是一个单一的索引,它就返回一个项目;如果 %key 是一个切片对象,它就返回一个切片序列。但是,我该如何区分这两种情况呢?

我基本上有两个假设。

sliced_list = self.wrapped_list[key]
if isinstance(key, slice):
    return MyCustomSequenceType(sliced_list, boolean_flag)
return sliced_list

但这样做是不是不太好呢?或者

sliced_list = self.wrapped_list[key]
try:
    return MyCustomSequenceType(sliced_list, boolean_flag)
except TypeError:
    return sliced_list

后者看起来更符合Python的风格。它依赖于 MyCustomSequenceType.__init__(self, datas, flag) 调用 len(datas),所以如果 %datas 是一个整数,就会抛出 TypeError。但是,如果 __init__ 因为其他随机问题抛出 TypeError,那就很难追踪了。此外,http://wiki.cython.org/enhancements/numpy/getitem 提到 isinstance 更快(实际上更容易优化)。

那么,我该怎么办呢?

2 个回答

2

这里应该是 isinstance(key, slice),而不是 isinstance(key, "slice")

另外,你不应该直接调用 __getitem__,而是应该使用 [] 这种方括号的方式来获取元素。

就我个人而言,如果我需要判断的话,我会使用 isinstance(key, slice) 方法,因为 slice 是个比较特殊的东西,不容易被其他类型替代(想想看,如果 self.wrapped_list 是一个 list,那么 slice 是唯一能返回其他内容而不是单个元素或错误的对象)。

所以我最后会这样写:

sliced_list = self.wrapped_list[key]
if isinstance(key, slice):
    return MyCustomSequenceType(sliced_list, boolean_flag)
return sliced_list

不过,你还要考虑一下是否真的需要特别对待切片;我不知道你的具体情况是什么,但在做出会影响后续的架构决策时,通常最好考虑几种不同的方法,评估一下,然后选择最合适的(虽然我自己不太这样做,我一般都是急匆匆地实现,然后再修补...)。

12

你可以看看标准库里的内容,看看里面是怎么做的。例如,calendar.py文件里有:

def __getitem__(self, i):
    funcs = self._months[i]
    if isinstance(i, slice):
        return [f(self.format) for f in funcs]
    else:
        return funcs(self.format)

这段代码展示了两种方法:一种是明确地检查数据类型,使用了isinstance,另一种则是通过直接把索引或切片传递给底层的列表,来部分地绕过这个问题。

撰写回答