1. 序列模式基础:什么是序列模式?

序列模式,说白了就是「有顺序的数据集合」。你想想看,我们平时写代码,最常打交道的就是列表、元组、字符串这些东西。它们都有一个共同特点——元素按固定顺序排列。

我个人习惯把序列模式理解为「排队买奶茶」。每个人站在固定的位置上,你不能随便插队,想找谁就按位置编号去找。这个编号,就是索引。

核心定义:序列模式是一种数据结构组织方式,其中元素按照确定的顺序排列,每个元素拥有唯一的位置编号(索引),并且支持从头到尾的遍历操作。

1.1 序列模式的三大核心特征

我在项目中遇到过不少新手把序列和集合搞混。其实区分起来很简单,记住三个特征就够了:

特征 说明 举个栗子
有序性 元素有固定的先后顺序,顺序本身携带信息 "abc" 和 "cba" 是不同的序列
索引访问 通过整数下标直接定位元素,时间复杂度 O(1) my_list[2] 拿到第三个元素
可迭代 可以用循环逐个取出元素,支持 for...in 语法 for item in sequence: ...

有序性——顺序就是信息

这一点我吃过亏。曾经有个项目,我用字典存了一组配置项,结果在不同 Python 版本下遍历顺序不一致,导致配置解析出错。后来改成列表,问题就解决了。

为什么会这样?因为字典在 3.7 之前不保证顺序,而序列永远保证。你放进去的顺序,就是它出来的顺序。

小技巧:当你需要「第一个是什么、第二个是什么」这种语义时,别犹豫,用序列。字典适合「根据名字找值」,序列适合「根据位置找值」。

索引访问——O(1) 的快乐

索引从 0 开始,这是 C 语言留下的传统。Python 还支持负数索引,-1 表示最后一个元素。嗯,这里要注意:索引越界会抛 IndexError,写代码时记得检查边界。

# 索引访问示例
fruits = ["苹果", "香蕉", "橘子", "葡萄"]

print(fruits[0])    # 苹果
print(fruits[-1])   # 葡萄
print(fruits[1:3])  # ['香蕉', '橘子']  —— 切片操作

可迭代——遍历的优雅

所有序列都是可迭代的。这意味着你可以用 for 循环、列表推导式、map/filter 等函数式工具来处理它们。我曾经在数据处理脚本里,用一行列表推导式替代了 8 行 for 循环,代码瞬间清爽不少。

# 可迭代的威力
numbers = [1, 2, 3, 4, 5]

# 普通写法
squares = []
for n in numbers:
    squares.append(n * n)

# 序列迭代写法
squares = [n * n for n in numbers]  # [1, 4, 9, 16, 25]

1.2 序列模式的知识体系

下面这张图是我自己梳理的序列模式知识结构,你可以把它当作本章的地图:

序列模式知识体系 序列模式 有序性 索引访问 可迭代 列表 (list) 元组 (tuple) 字符串 (str) 切片 [start:stop:step] 拼接 + / 重复 * 成员检测 in / not in 💡 核心要点 序列模式 = 有序 + 索引 + 可迭代 常见序列:列表(可变)、元组(不可变)、字符串(不可变)

1.3 序列 vs 非序列:一张表看懂

很多同学问我:「什么时候用序列,什么时候用集合或字典?」我的回答是:看你要不要「顺序」这个属性。

对比维度 序列模式 非序列模式(集合/字典)
顺序保证 ✅ 严格有序 ❌ 无序(或插入顺序,不保证位置语义)
访问方式 索引(整数下标) 键(key)或哈希值
重复元素 ✅ 允许重复 ❌ 集合不允许,字典 key 不允许
典型场景 排行榜、队列、文本处理 去重、缓存、映射关系
时间复杂度 索引 O(1),查找 O(n) 查找 O(1) 平均

避坑指南:我曾经在日志分析系统里用列表存了 10 万条记录,然后频繁用 if item in my_list 做查找。结果性能惨不忍睹。后来换成集合,速度提升了上百倍。记住:查找频繁用集合,顺序重要用列表。

1.4 序列模式的通用操作

不管哪种序列类型,都支持下面这些操作。我建议你把这些记牢,写代码时能省不少事:

# 序列通用操作一览
seq = [1, 2, 3, 4, 5]

# 1. 索引访问
seq[0]      # 1
seq[-1]     # 5

# 2. 切片
seq[1:4]    # [2, 3, 4]
seq[::2]    # [1, 3, 5]

# 3. 拼接与重复
seq + [6, 7]    # [1, 2, 3, 4, 5, 6, 7]
seq * 3         # [1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]

# 4. 成员检测
3 in seq        # True
10 not in seq   # True

# 5. 长度与最值
len(seq)        # 5
max(seq)        # 5
min(seq)        # 1

# 6. 遍历
for i, val in enumerate(seq):
    print(f"位置 {i} 的值是 {val}")

个人经验:enumerate() 是我最常用的函数之一。它同时给你索引和值,比 range(len(seq)) 优雅得多。我写代码时几乎不用 range(len(...)) 这种写法了。

1.5 序列模式的边界与局限

序列模式不是万能的。我遇到过几个典型问题,分享给你:

  • 插入/删除效率低:在列表头部插入元素是 O(n) 操作。如果你频繁在两端操作,考虑用 collections.deque。
  • 查找效率低:线性查找 O(n)。数据量大时,考虑用集合或二分查找(前提是已排序)。
  • 内存占用:序列存储所有元素,不像生成器那样惰性求值。处理超大数据集时注意内存。

嗯,到这里你应该对序列模式有了整体认识。记住三个关键词:有序、索引、可迭代。后面我们会深入每种序列类型的具体用法和坑点。