跳转到内容

第 2 章 · 序列

一句话:Python 的序列类型有一张共同的接口,认熟它,就不用每种类型重新学一遍。

字符串、列表、元组、字节串、array、XML 元素、数据库查询结果,都共享一套操作: 迭代、切片、排序、拼接、解包。你在 list 上学到的东西,大部分能直接搬到别的序列上。

分法一:能改 vs 不能改。

例子
可变序列 list、bytearray、array.array、collections.deque
不可变序列 tuple、str、bytes

分法二:装引用 vs 存值。

装什么 例子 特点
容器序列(container) 一堆指向对象的引用 list、tuple、deque 灵活,能嵌套任意类型
扁平序列(flat) 自己的内存里直接放机器值 str、bytes、array.array 紧凑、快,但只能放数字/字符/字节

这个区分不是术语洁癖,它直接决定内存占用。我在本机量了一下,同样 1000 个浮点数:

list 对象(头 + 指针数组) 8056 字节
list 里 1000 个 float 对象 24000 字节
list 总占用 32056 字节
array 总占用 8080 字节

array 省下的约 4 倍内存,全部来自「不给每个数单独造一个对象」。内存里的一个 float 对象是 ob_refcnt + ob_type + ob_fval 三个字段,64 位下每个 8 字节;list 里 每个元素还要再存一个 8 字节指针。

页 讲什么 我的结论
推导式与生成器表达式 listcomp 和 genexp 造列表用 listcomp,喂别的构造器用 genexp
元组的两副面孔 记录 vs 不可变列表 「不可变」只管引用,管不到引用指向的对象
解包 * 的各种用法 不用下标取值,就不用写错下标
序列模式匹配 match/case 不是 switch,是解构加类型检查
切片 切片对象、切片赋值 切片可以取名字,左边也能放切片
+ 和 * 和 += 拼接与原地修改 [[]] * 3 是个陷阱,+= 对元组是造新对象
排序 sort / sorted / key 稳定排序,key 只调一次
列表之外 array / memoryview / deque 数字多就换 array,两端增删就换 deque
终端窗口
uv run pytest tests/test_ch02.py -v
cd chapters/ch02 && uv run python -c "import pitfalls; print(pitfalls.augmented_assignment_puzzler())"

chapters/ch02/ 下七个模块,对应上面七页里的可运行部分。