如何高效判断自定义__getitem__方法的"key"参数是否为切片?
我有一个自定义的序列类型。它基本上是一个列表的包装,加上一个布尔标志,我想让它表现得像通常的不可变序列。
我遇到的问题是关于切片的。我知道在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 个回答
这里应该是 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
不过,你还要考虑一下是否真的需要特别对待切片;我不知道你的具体情况是什么,但在做出会影响后续的架构决策时,通常最好考虑几种不同的方法,评估一下,然后选择最合适的(虽然我自己不太这样做,我一般都是急匆匆地实现,然后再修补...)。
你可以看看标准库里的内容,看看里面是怎么做的。例如,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
,另一种则是通过直接把索引或切片传递给底层的列表,来部分地绕过这个问题。