在 Python 里,像列表(list)、元组(tuple)和字符串(str)这类 序列类型都支持切片操作,但是实际上切片操作比人们所想象的要强大很多。
切片
最后一个元素
在切片和区间操作里不包含区间范围的最后一个元素是 Python 的风格, 这个习惯符合 Python、C 和其他语言里以 0 作为起始下标的传统。这样 做带来的好处如下。
- 当只有最后一个位置信息时,我们也可以快速看出切片和区间里有 几个元素:range(3) 和 my_list[:3] 都返回 3 个元素。
- 当起止位置信息都可见时,我们可以快速计算出切片和区间的长 度,用后一个数减去第一个下标(stop - start)即可。
- 这样做也让我们可以利用任意一个下标来把序列分割成不重叠的两部分,只要写成
my_list[:x]
和my_list[x:]
就可以了
对象切片
一个众所周知的秘密是,我们还可以用 s[a:b:c]
的形式对 s 在 a 和 b 之间以 c 为间隔取值。c 的值还可以为负,负值意味着反向取值。
a:b:c
这种用法只能作为索引或者下标用在 [] 中来返回一个切片对 象:slice(a, b, c)
。对 seq[start:stop:step]
进行求值的时候,Python 会调用 seq.__getitem__(slice(start, stop, step))
。
多维切片和省略
- [] 运算符里还可以使用以逗号分开的多个索引或者是切片,外部库 NumPy 里就用到了这个特性,二维的
numpy.ndarray
就可以用a[i, j]
这种形式来获取,抑或是用a[m:n, k:l]
的方式来得到二维切片。 - 要正确处理这种 [] 运算符的话,对 象的特殊方法
__getitem__
和__setitem__
需要以元组的形式来接收a[i, j]
中的索引。也就是说,如果要得到a[i, j]
的值,Python 会调用a.__getitem__((i, j))
。 - Python 内置的序列类型都是一维的,因此它们只支持单一的索引,成对出现的索引是没有用的。
- 省略(ellipsis)的正确书写方法是三个英语句号(…),而不是 Unicdoe 码位 U 2026 表示的半个省略号(…)。省略在 Python 解析器眼 里是一个符号,而实际上它是 Ellipsis 对象的别名,而 Ellipsis 对象又是 ellipsis 类的单一实例。
- 它可以当作切片规范的一部分,也可 以用在函数的参数清单中,比如 f(a, …, z),或 a[i:…]。在 NumPy 中,… 用作多维数组切片的快捷方式。如果 x 是四维数组,那 么 x[i, …] 就是 x[i, :, :, :] 的缩写。
给切片赋值
如果把切片放在赋值语句的左边,或把它作为 del 操作的对象,我们就 可以对序列进行嫁接、切除或就地修改操作。
代码语言:javascript复制l = list(range(10))
--> l [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
l[2:5] = [20, 30]
--> l [0, 1, 20, 30, 5, 6, 7, 8, 9]
del l[5:7]
--> l [0, 1, 20, 30, 5, 8, 9]
l[3::2] = [11, 22]
--> l [0, 1, 20, 11, 5, 22, 9]
l[2:5] = [100]
--> l [0, 1, 100, 22, 9]
如果赋值的对象是一个切片,那么赋值语句的右侧必须是个可迭代 对象。即便只有单独一个值,也要把它转换成可迭代的序列。
参考资料
- 流畅的Python(2017年人民邮电出版社出版)