第2章 序列构成的数组

按《Fluent Python, 2nd Edition》第2章重建:序列构成的数组、列表推导式与生成器表达式、元组、解包与序列模式匹配、切片与增量赋值、数组、内存视图与双端队列。

从一个错误直觉开始

先预测:只记住序列构成的数组的语法,是否足以写出可靠实现?不够。真正需要掌握的是对象、协议、状态和失败路径怎样协作。不是孤立技巧,而是把调用方意图映射到可测试行为的模型。

核心模型与责任

序列构成的数组先区分容器序列与扁平序列,再区分可变与不可变。list保存对象引用,array保存同质机器值;选择结构时要先写出元素类型、访问方式和更新需求。 这一章的阅读方法是先写出输入和不变量,再观察解释器或标准库采取哪条路径,最后用反例确认边界。这样学习得到的是可迁移的判断,而不是只能复述示例。

机制一:第一条执行链

列表推导式用于立即构造列表,生成器表达式把值按需送入构造器或消费端。推导式的目标应是构造新序列,若只是为了副作用,普通循环会更清楚。

symbols = '$¢£¥€¤'
codes = [ord(symbol) for symbol in symbols]
utf8 = tuple(ord(symbol) for symbol in symbols)

运行后记录对象身份、返回类型和异常位置;再改变一个输入,确认变化来自协议本身,而不是偶然的实现细节。

机制二:状态、类型与协作

元组既可作为不可变序列,也可作为无字段名记录。扩展解包、嵌套解包和序列模式匹配能把结构约束写在赋值位置,并用星号捕获剩余元素。

record = ('Tokyo', 'JP', 36.933, (35.689, 139.692))
city, country, population, (lat, lon) = record
match record:
    case [name, 'JP', _, [_, longitude]]: print(name, longitude)

评审这段代码时,先问调用端依赖什么能力,再问实现是否扩大了共享状态或静默吞掉错误。接口越小,替换和测试通常越直接。

机制三:边界条件与成本

切片是半开区间并生成新对象;给切片赋值可以改变长度。增量赋值是否原地更新取决于对象是否实现iadd,可变list通常保留身份,不可变tuple会重新绑定。 数组、内存视图与双端队列分别解决紧凑数值存储、零复制重解释和两端高效操作。deque中间访问较慢,memoryview共享底层缓冲区,因此别名与生命周期必须可见。

from array import array
from collections import deque
numbers = array('d', [1.0, 2.0, 3.0])
view = memoryview(numbers)
queue = deque(range(5), maxlen=5)
queue.rotate(2)

分步验证

代码实验与诊断

把三段代码保存为同一最小实验,先运行原始版本,再只改变一个维度。至少检查:公开结果是否稳定、失败是否在正确边界暴露、是否产生意外别名或资源泄漏、类型提示与运行时行为是否一致。观察变化后写出因果解释,而不是只记录输出。

常见误区

本章回顾

官方核心单元核对:序列构成的数组;列表推导式与生成器表达式;元组、解包与序列模式匹配;切片与增量赋值;数组、内存视图与双端队列。这些单元共同回答序列构成的数组如何从语言机制落到工程边界;下一步应能在没有范例答案时画出执行链、实现最小版本并解释反例。

术语表

讨论

评论区加载中…