python切片是基于__getitem__和slice对象的机制:切片语法如a[1:5:2]被转为slice(1,5,2)传入,slice.indices(n)自动处理默认值、负索引与边界,确保安全可靠。

Python切片不是语法糖,而是一套有明确规则的机制:对象只要实现 __getitem__ 方法并能接收 slice 实例,就天然支持切片。核心在于 slice 对象的构造与解释。
切片字面量如何变成 slice 对象
当你写 a[1:5:2],Python 解析器会自动构造一个 slice(1, 5, 2) 对象,并把它作为参数传给 a.__getitem__()。等价于:
a.__getitem__(slice(1, 5, 2))- 省略写法如
a[:]→slice(None, None, None) -
a[::2]→slice(None, None, 2) -
a[3:]→slice(3, None, None)
slice 对象的三个属性与默认行为
每个 slice 实例有 start、stop、step 三个只读属性,值可能是 None。解释逻辑由被切对象自己决定,但内置类型(如 list、str)遵循统一规则:
- 若
step > 0(正向),默认start = 0,stop = len(obj) - 若
step (反向),默认 <code>start = -1,stop = -(len(obj)+1) -
None在不同位置含义不同,不能简单等同于 0 或长度 - 负索引在计算前会先按
len(obj) + i归一化(例如-1变成len-1)
自定义类支持切片的关键:正确处理 slice 参数
只需在 __getitem__ 中判断参数是否为 slice 实例,再手动解析逻辑。例如:
立即学习“Python免费学习笔记(深入)”;
class MySeq:
def __init__(self, data):
self.data = data
<pre class='brush:python;toolbar:false;'>def __getitem__(self, key):
if isinstance(key, slice):
# 手动处理 start/stop/step,默认值和负索引
start, stop, step = key.indices(len(self.data))
return [self.data[i] for i in range(start, stop, step)]
else:
return self.data[key]
注意:slice.indices(n) 是关键辅助方法——它把任意 slice 对象映射为三元组 (start, stop, step),其中所有值都是非负整数且已适配序列长度 n,避免手动处理边界和负索引错误。
为什么 indices() 比手动计算更可靠
直接用 key.start or 0 这类写法会出错,因为 None 和负数需结合长度重新计算。而 slice.indices(n) 内部已封装全部规则:
-
slice(1, None, 2).indices(10)→(1, 10, 2) -
slice(None, None, -1).indices(5)→(4, -1, -1) -
slice(-3, -1).indices(10)→(7, 9, 1)
这是标准库推荐做法,也是 list、str 等底层实际使用的逻辑。









