切片
三个常被忽略的点:
slice(a, b, c)是一等公民对象,可以取名字,不用把数字散在代码里。- 切片放在赋值号左边,能原地改可变序列,不用重建整个列表。
a:b:c只在[]里合法。seq[1:3]实际调用的是seq.__getitem__(slice(1, 3))。
为什么切片不含末尾
Section titled “为什么切片不含末尾”这个约定不是随意定的,它带来三个很方便的性质:
>>> l = [10, 20, 30, 40, 50, 60]>>> l[:2] # 只给 stop,长度一眼看出是 2[10, 20]>>> l[2:] # 从 2 切到底[30, 40, 50, 60]| 性质 | 说明 |
|---|---|
| 只看 stop 就知道长度 | range(3) 和 l[:3] 都是 3 项 |
| 长度就是 stop - start | 不用 ±1 修补 |
| 在任意位置一刀两断不重叠 | l[:x] + l[x:] 正好拼回原序列,无重无漏 |
我把它写成了测试:
left, right = splitting_at(2, values)assert len(left) + len(right) == len(values) # 不漏assert left == [10, 20] # 不重步长可以是负数
Section titled “步长可以是负数”>>> s = 'bicycle'>>> s[::3]'bye'>>> s[::-1]'elcycib'>>> s[::-2]'eccb'第 1 章那个 deck[12::13] 也是这个用法 —— 从下标 12 开始,每次跳 13 步,
正好把四张 A 都挑出来。
切片对象可以取名字
Section titled “切片对象可以取名字”这是我最喜欢的一个技巧。假设要解析这种定长文本:
0.....6.................................40........52...55........1909 Pimoroni PiBrella $17.50 3 $52.50不要在每个地方写 line[40:52],把切片存成变量:
SKU = slice(0, 6)DESCRIPTION = slice(6, 40)UNIT_PRICE = slice(40, 52)QUANTITY = slice(52, 55)ITEM_TOTAL = slice(55, None)
for item in line_items: print(item[UNIT_PRICE], item[DESCRIPTION])读的时候不用去数「第 40 到第 52 个字符是什么来着」。跟电子表格里给单元格区域命名是一回事。
切片放在左边:原地改
Section titled “切片放在左边:原地改”可变序列可以用切片做嫁接、切除、替换:
>>> l = list(range(10))>>> l[2:5] = [20, 30] # 3 个位置换成 2 个元素,长度变了>>> 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] # 步长不为 1 时,个数必须刚好对上>>> l[0, 1, 20, 11, 5, 22, 9]
>>> l[2:5] = 100TypeError: must assign iterable to extended slice>>> l[2:5] = [100] # 想放一项,得写成列表>>> l[0, 1, 100, 22, 9]多维切片和省略号
Section titled “多维切片和省略号”[] 可以收逗号分隔的多个下标。a[i, j] 传进 __getitem__ 的其实是一个元组:
a[i, j] -> a.__getitem__((i, j))NumPy 的二维数组就是这么工作的。a[m:n, k:l] 是一个二维切片。
...(三个英文句点,不是 Unicode 省略号 …)是 Python 的一个词法记号,
指向 Ellipsis 对象。NumPy 用它做多维切片的快捷写法:x[i, ...] 等价于
x[i, :, :, :]。
Python 内置类型里只有 memoryview 支持多维。标准库里我没找到别的用处 ——
这两个语法主要是给 NumPy 这类扩展留的口子。
test_splitting_has_no_overlap_and_no_gap—— 一刀两断不漏不重test_assign_to_slice—— 四步操作之后的最终结果test_assign_to_slice_needs_iterable—— 抛TypeErrortest_slice_object_is_hashable——slice可哈希,能当 dict 的键