修改__getitem__后无法对列表进行切片



对于一个特定的用例,我想定义一个列表类,如果索引为负数或超出范围,该类将返回0。

我目前的方法已经达到了特定的目的:

class mlist(list):
def __getitem__(self, n):
if (len(self)<=n) or (n<0):
return 0
return super(mlist, self).__getitem__(n)
l = mlist([1,2,3,4])
l[-2]
>>> 0
l[10]
>>> 0

但不幸的是,在对列表进行切片时,它会导致一些不良行为:

l[0:2]
>>> TypeError: '<=' not supported between instances of 'int' and 'slice'

有办法解决这个问题吗?

您希望取消显示IndexError,而返回0。所以,你可以选择:

class mlist(list):
def __getitem__(self, n):
try:
return super().__getitem__(n)
except IndexError:
return 0

然而,这允许像通常的列表一样进行负索引(从末尾访问((因为这不会引发IndexError(。如果你也想抑制这种情况,你可以试试:

class mlist(list):
def __getitem__(self, n):
try:
if n < 0 or n >= len(self):
return 0
return super().__getitem__(n)
except TypeError:
return super().__getitem__(n)

假设n是int,并相应地工作,如果不是,则将在比较中引发TypeError,并调用super方法。然后,当传递无效类型(例如字符串(时,它既处理切片,又抛出适当的错误。

问题是,参数n是方括号之间传递的任何内容,无论是索引(因此类型为int(还是切片(类型为slice(。

当前代码仅在n属于int类型的情况下有效,它不能正确处理切片。

如果您想保持切片功能与默认功能相同,为什么不调用super().__getitem__(n)呢?

class mlist(list):
def __getitem__(self, n):
# If n is a slice
if isinstance(n, slice):
return super().__getitem__(n)
# Otherwise
if len(self)<=n or n<0:
return 0
return super(mlist, self).__getitem__(n)

但是,如果您想为切片实现自己的逻辑,可以在if isinstance(n, slice):块中实现。