ele*_*ent 6 python indexing exception slice
在Python文档指出,
切片索引被静默截断以落在允许的范围内
因此IndexErrors,无论使用什么start或stop参数,切片列表时都没有上升:
>>> egg = [1, "foo", list()]
>>> egg[5:10]
[]
Run Code Online (Sandbox Code Playgroud)
由于列表egg中不包含任何大于的索引2,因此a egg[5]或egg[10]call会引发IndexError:
>> egg[5]
Traceback (most recent call last):
IndexError: list index out of range
Run Code Online (Sandbox Code Playgroud)
现在的问题是,当给定的切片指数超出范围时,我们如何提出IndexError?
这里没有灵丹妙药。你必须测试两个边界:
def slice_out_of_bounds(sequence, start=None, stop=None, step=1):
length = len(sequence)
if start is None: # default depends on step direction
start = length - 1 if step < 0 else 0
elif start < 0: # relative to length
start += length
if stop is None: # default depends on step direction
stop = -1 if step < 0 else length
elif stop < 0: # relative to length
stop += length
# stop can range [0 .. length] for positive steps or
# [-1 .. (length - 1)] for negative steps (both bounds inclusive).
# adjust stop for negative steps to make the bounds check easier.
if step < 0:
stop += 1
if not (0 <= start < length and 0 <= stop <= length):
raise IndexError("Container slice indices out of bounds")
Run Code Online (Sandbox Code Playgroud)
注意我们需要特殊处理的方式stop。切片中的最终值是独占的,因此允许范围最大为length。对于负步长,有效值stop位于范围内[-1 .. length)(或[-1 .. (length - 1)]包含边界),但向该stop值添加 1 可以重复使用相同的0 <= stop <= length测试。
__getitem__()如果您使用方法创建自己的容器类,则对容器进行切片会为您提供一个slice()实例。在这种情况下,不要使用该slice.indices()方法,它会为您调整边界,而不是引发IndexError. 相反,我们使用.start,.stop和.step属性。其中每一个都可以是None,包括.step,所以也请确保处理好它。
这是__getitem__上述的一个版本,添加了一些针对其他边缘情况的检查,以复制list切片的工作原理:
class SomeContainer:
...
def __getitem__(self, key):
length = len(self)
if isinstance(key, int) and not (0 <= key < length):
raise IndexError("Container index out of range")
elif isinstance(key, slice):
if key.step == 0:
raise ValueError("Slice step cannot be zero")
start, stop, step = key.start, key.stop, key.step or 1
if start is None: # default depends on step direction
start = length - 1 if step < 0 else 0
elif start < 0: # relative to length
start += length
if end is None: # default depends on step direction
end = -1 if step < 0 else length
elif end < 0: # relative to length
end += length
# end can range [0 .. length] for positive steps or
# [-1 .. (length - 1)] for negative steps (both bounds inclusive).
# adjust end for negitive steps to make the bounds check easier.
# Don't do this if you also wanted to calculate the slice length!
if step < 0:
end += 1
if not (0 <= start < length and 0 <= end <= length):
raise IndexError("Container slice indices out of bounds")
else:
raise TypeError(f"list indices must be integers or slices, not {type(key)}")
Run Code Online (Sandbox Code Playgroud)