P2-8.2 列表(list):有顺序的值集合¶
Section ID:
P2-8.2Version:v2026.07.23
在 P2-8.1 中,我们看过了值(value)、变量(variable)、类型(type)。现在来看第一个可以一次处理多个值的结构:列表(list)。
列表是一种把同一目的或同一语境中的值按顺序收集起来的数据结构(data structure)。像分数列表、句子列表、文件名列表、模型输出列表这类“想按顺序查看多个值”的场景里,经常会遇到它。
这里会说明 列表(list) 和 索引(index) 的基本区分。值(value)、变量(variable)、类型(type) 的代表性说明放在 P2-8.1 和 概念词典 中,而这里集中处理的是:当值变成多个之后,为什么首先需要一种有顺序的集合结构。
如果前一节处理的是 单个值如何以某个名字和某个类型存在,那么这里处理的就是:当这样的值变成多个时,为什么首先需要一种有顺序的集合。如果这个标准先建立起来,那么紧接着下一节里的字典(dictionary)也会更容易读成 不是另一种语法,而是用名字查找、而不是按顺序查找的结构。
| 本节要先抓住什么 | 紧接着会出现什么问题 | 之后会在什么地方再次使用 |
|---|---|---|
| 列表是有顺序的值集合 | 这会接到 P2-8.3 中“它与按名字查找的字典有什么不同”。 | 之后在阅读 NumPy 数组、文件列表、模型输出集合时会反复出现。 |
| 索引是按位置把值再次取出来的方法 | 这会接到 P2-8.4 中“通过迭代按顺序处理多个值”的场景。 | 之后又会连到切片、数组轴读取、DataFrame 局部查看。 |
| 列表是 mutable value,因此可能会一起变化 | 这会接到补充学习 P2-8.7 中关于引用与复制的区分。 | 之后在预处理示例、中间结果保存、调试中会持续重要。 |
| 术语 | 本节先要抓住的意思 |
|---|---|
| 列表(list) | 有顺序的值集合。 |
| 索引(index) | 指向集合内部位置的编号。 |
| 项(item) | 列表中的单个值。 |
| mutable value | 可以添加或修改项的值结构。 |
| 嵌套列表(nested list) | 列表里面再次放入列表的结构。 |
核心判断标准:列表(list):有顺序的值集合¶
- 能把列表(list)解释为有顺序的值集合。
- 能说明索引(index)从 0 开始。
- 能区分“带着已知值开始的列表”“空列表”“用同样的值填满的列表”。
- 能说明列表是 mutable value。
- 能把分数、句子、模型输出、文件名列表都读成 AI 实践里的列表。
先抓住的标准¶
本节最先要抓住的标准是:列表是有顺序的值集合。
| 现在看到的场景 | 先想起的问题 |
|---|---|
[82, 75, 91, 68] | 第几个值重要? |
scores[0] | 是不是通过位置把值再次取出来? |
scores.append(68) | 是不是在改变现有集合本身? |
rows = [[1, 2], [3, 4]] | 即使看起来像二维,它仍然只是列表里面放列表吗? |
也就是说,必须先建立这样的感觉:列表是一种 按顺序放进去、按位置取出来、必要时还能改动的结构。
三个标准¶
这里先看的不是 Python 语法,而是 如何把多个值一次性处理起来。下面三个标准会成为以后阅读字典、迭代和数组说明时的基础。
| 标准 | 为什么重要 | 本节所需的理解程度 |
|---|---|---|
| 列表是有顺序的值集合 | 它是抓住与字典差异的出发点 | 理解这是一个“第几个值”很重要的结构 |
| 索引是位置编号 | 之后会连到切片、数组和 DataFrame 的读取 | 用“第一个值从 0 开始”这个规则来理解 |
| 列表是可变化的值 | 它能解释为什么在预处理和示例代码里值会一起变 | 记住两个名字可能同时看到同一个列表 |
列表是有顺序的值集合¶
一般来说,有顺序的集合,就是把多个值按照一定顺序摆放起来,再通过位置(index)把它们取出来的结构。像分数列表、句子列表、文件列表这种“第几个值”本身就有意义的场景,需要这样的结构。
在 Python 中,这种结构通常通过列表(list)来表达。
问题场景:我想先看看把多个分数表示成一个有顺序集合的最基本形状。 输入(input):四个分数 82, 75, 91, 68。 期望输出(output):会输出分数列表以及它的类型。 要确认的概念:列表是按顺序存放多个值的基本结构。
Python 列表中的每个值都可以称作项(item)或元素(element)。
因为 Python 列表有顺序,所以可以通过位置(index)把值取出来。
问题场景:我想确认怎样通过位置把列表中的第一个值和第二个值取出来。 输入(input):分数列表 scores。 期望输出(output):打印 scores[0] 和 scores[1] 的值。 要确认的概念:列表中的值通过索引访问,而在 Python 中通常从 0 开始计数。
Python 中的索引(index)通常从 0 开始。所以 scores[0] 是第一个值。这里重要的不是背规则本身,而是理解:值是按某种顺序放进去的,并且可以按位置再取出来。
| 表达 | 含义 | 值 |
|---|---|---|
scores[0] | 第一个项 | 82 |
scores[1] | 第二个项 | 75 |
scores[-1] | 最后一个项 | 68 |
这种从 0 开始的规则一开始可能有些陌生。但 Python 字符串、列表以及后面会遇到的 NumPy 索引里,都会反复出现这种从 0 开始计数的方式。这里重要的不是把列表叫成数组,而是先抓住这种感觉:只要是有顺序的结构,就可能需要位置编号。
| 视角 | 一般说明 | 在 Python 中 |
|---|---|---|
| 有顺序的集合 | 按顺序摆放多个值的结构 | 使用列表(list) |
| 位置(index) | 在集合中查找值的编号 | 通常从 0 开始 |
| 项(item) | 集合中的单个值 | 可以像 scores[0] 一样取出 |
列表并不是数组的替代词¶
先学过其他语言的人,可能会马上把列表(list)理解成数组(array)。因为两者都有顺序,也都能按位置(index)取值。
但在本节中,我们不会把列表和数组当成同一个词来用。Python 列表更接近一种通用容器(container):里面可以放多个值,并按顺序处理。而在 AI 数值计算里说的数组(array),通常指的是把同一种数字按固定结构摆好、为了快速计算而设计的数据结构。
Python 官方文档也支持这种区分。list 被描述为可变序列(mutable sequence),而标准库中的 array 模块则另外提供了高效存储数值的数组。array 在某些行为上像列表,但它能存放的值类型受到创建时 type code 的限制。
当看到多维数组时,这种混淆会更强。在 Python 中,如果把列表放进列表里,也能做出看起来像表格的结构。
问题场景:我想先看看,当列表里面再放列表时,会形成一种看起来像表格的结构。 输入(input):两行列表 [1, 2, 3]、[4, 5, 6]。 期望输出(output):嵌套列表 rows。 要确认的概念:嵌套列表即使看起来像二维结构,本质上仍然是列表里面放列表。
这个形状看起来像矩阵(matrix)或二维数组(two-dimensional array)。但它本质上仍然只是 列表里面放了列表的结构。NumPy 的多维数组(ndarray)则是一种带有 shape、axis、dtype 等信息的计算结构,NumPy 文档也把 ndarray 描述为 N 维数组。因此,嵌套列表看起来像矩阵 和 嵌套列表就是数值计算用的多维数组 必须区分开。
| 视角 | Python 列表(list) | 数值计算里的数组(array)视角 |
|---|---|---|
| 核心想法 | 有顺序的值集合 | 把同一种数值按结构放好、作为计算对象 |
| 主要用途 | 保存样本列表、文件名、文本列表等多个对象 | 对向量、矩阵、模型输入等执行数值计算 |
| 值的种类 | 可以放不同类型,但通常还是放同一目的的值 | 通常期待相同的数值类型 |
| 修改方式 | 容易追加或删减值 | 更关心大小、轴(axis)和运算方式 |
| 本节位置 | Python 基础语法恢复 | 会在 Part 2 Chapter 3 和 Part 2 Chapter 11 另行处理 |
所以在这一节里,只把列表读成 有顺序的值集合。为了快速数值计算而使用的数组(array)、向量(vector)、矩阵(matrix),会在 Part 2 Chapter 3 与 Part 2 Chapter 11 里单独处理。
这个区分非常重要。Python 列表很适合收集多个样本,但在模型计算中,如果要快速处理大量数字,通常会使用 NumPy 数组(array)这类专门结构。因此,列表能装数字 和 列表就是数值计算数组 并不是同一句话。
列表和其他数据结构承担的角色不同¶
Python 列表的设计可以理解成这样一种结构:它是一个可变序列(mutable sequence),能够按顺序存放值,需要时可以从末尾追加或取出,也方便反复处理。 Python 官方教程也会分别说明列表方法、把列表当栈(stack)用的方式、把它当队列(queue)时的局限,以及字典(dictionary)、集合(set)、元组(tuple)等不同结构。
也就是说,列表不是所有“集合”都可以代替的结构。应该根据“你准备用什么标准去处理值”来选择不同结构。
| 结构 | 中心问题 | 和列表的差异 |
|---|---|---|
| 列表(list) | 是否要把多个值按顺序存放并逐个处理? | 位置(index)和顺序重要,而且值可以增加或修改 |
| 元组(tuple) | 是否要把它保持成一个不会变化的集合? | 元组是 immutable sequence,更接近固定值集合 |
| 字典(dictionary) | 是否要通过名字或键(key)来找值? | 不是按位置,而是按 key 访问值 |
| 集合(set) | 是否更关心无重复元素和包含关系? | 比起顺序,更关心唯一性和 membership test |
| 双端队列(deque) | 是否会频繁地从两端插入或取出? | 如果像队列一样经常从前面取,collections.deque 比列表更合适 |
| 数组(array) | 是否要结构化地计算同类型数值? | 更关心数值类型、shape、axis 和运算方式 |
因此,看列表时,与其先问“它是不是数组”,不如先问“它是不是一个有顺序的通用集合”。列表是 Python 代码里最常见的基础结构,但一旦计算目的更明确,就需要把思路转向字典、集合、双端队列、NumPy 数组等其他结构。
把这种差异再简短总结一下:
| 现在需要的问题 | 先想到的结构 |
|---|---|
| 这是第几个值? | 列表(list) |
| 是通过名字查找吗? | 字典(dictionary) |
| 是在计算同类型数字吗? | 数组(array)、NumPy |
列表可以添加和修改值¶
列表是可以变化的值(mutable value)。如果先理解这一点,后面再读“从空列表开始收集值”的模式,以及“先用相同值把长度填满”的模式时,就能更小心一些。
问题场景:我想直接确认列表创建后仍然可以添加和修改值。 输入(input):初始分数列表,以及 append 和索引赋值。 期望输出(output):一个添加了值并修改了部分项的列表。 要确认的概念:列表是可变值,既可以在末尾追加,也可以按位置修改。
append() 会把值加到列表末尾。scores[1] = 77 会把第二个项改掉。
在 P2-8.1 中,我们说过 变量是贴在值上的名字。在列表这里,这个视角会更加重要。
问题场景:我想看看当同一个列表被两个名字同时指向时,通过其中一个名字修改,另一个名字是否也会看到变化。 输入(input):都指向同一个列表的 scores 与 other_scores。 期望输出(output):两个名字都会打印出相同的变化结果。 要确认的概念:把列表赋给另一个变量,并不一定会自动得到复制品。
scores 和 other_scores 并不是两个不同列表的复制,而是指向同一个列表。所以,通过一个名字追加值后,从另一个名字去看,也会看到同样的变化。
在这一节里,只先留下下面这些标准。
- 修改一个数字或字符串的感觉,和修改列表的感觉可能不同。
- 把列表赋给另一个名字,并不会自动产生新的副本。
- 如果数据预处理中必须保留原始列表,就要认真对待是否复制。
复制与 原对象和副本什么时候会一起变化 这个问题,会在紧接着的补充学习 P2-8.7 中重新整理。
列表可以通过简洁语法来连接、切割和修改¶
在阅读 Python 列表时,往往会先看到符号和方括号语法,而不是函数名。在其他语言里也许会通过 concat、join、slice、splice 等名字遇到的动作,在 Python 里有时则通过运算符(operator)、切片(slice)、赋值语句(assignment)、del 语句来表达。
这里重要的不是“Python 列表里一定有这些名字的函数”,而是 Python 提供了一套处理序列(sequence)的通用语法,而列表经常使用这套语法。
把列表接起来:连接(concatenation)¶
当你想把两个列表接起来并创建一个新列表时,可以使用 +。如果想把其他值追加到已有列表末尾,可以使用 extend()。
问题场景:我想比较 + 和 extend() 虽然都能连接列表,但修改原列表的方式是否不同。 输入(input):front、back、scores。 期望输出(output):新创建的 combined、保持不变的 front、被修改后的 scores。 要确认的概念:+ 会创建连接后的新列表,而 extend() 会修改已有列表本身。
+ 是创建一个新的连接结果,而 extend() 会直接修改现有列表。这个差异在后面区分引用与修改时非常重要。
切列表:切片(slice)¶
当只想取出列表的一部分时,可以使用切片(slice)。
问题场景:我想一次看清从列表中切出前面、中间、后面一部分的方式。 输入(input):包含五个分数的 scores。 期望输出(output):分别输出中间区间、前两个值、后面区间。 要确认的概念:切片是通过指定起点和终点范围来读取一部分区间的语法。
scores[1:4] 会从索引 1 取到索引 4 之前。因此结果是 [75, 91, 68]。结束位置不包含在内 这个规则一开始会显得陌生,但它会在 Python 字符串和列表中反复出现。
切片是一种从原列表中读取部分区间的语法。
删除或替换列表的一部分:删除与切片赋值¶
像其他语言里的 splice 那样,删除或替换列表中间的一段,在 Python 中并没有作为单独的 splice() 方法提供。类似目的会通过 del、insert() 和切片赋值(slice assignment)来表达。
问题场景:我想确认删除列表中间一段后,会剩下什么结果。 输入(input):items = ["A", "B", "C", "D"],以及删除范围 1:3。 期望输出(output):一个中间两个项被移除后的列表。 要确认的概念:把 del 和切片结合起来,就能删除特定区间。
del items[1:3] 会删除从索引 1 到索引 3 之前的部分。结果是 ["A", "D"]。
也可以把某个区间换成其他值。
问题场景:我想确认列表的一段能否替换成长度不同的值列表。 输入(input):区间 items[1:3] 和新值 ["X", "Y", "Z"]。 期望输出(output):替换区间后得到的列表。 要确认的概念:切片赋值即使长度不同,也可以替换整个区间。
结果是 ["A", "X", "Y", "Z", "D"]。也就是说,被替换区间并不要求长度完全一致。
join 不是列表动作,而是字符串动作¶
join 在 Python 中经常出现,但它不是列表方法。它是字符串(str)在把字符串列表连接成一个整体字符串时使用的方法。
问题场景:我想看看当把字符串列表合成一句话时,join 是怎么用的。 输入(input):字符串列表 words 和分隔符 " "。 期望输出(output):用空格连接后的句子 sentence。 要确认的概念:join() 属于字符串这边,而不是列表这边。
结果是 "AI needs data"。在这里,真正执行动作的主体不是列表,而是字符串 " "。这个字符串负责把 words 中的字符串用空格连接起来。
因此,在 Python 中阅读列表时,最好像下面这样区分。
| 想做的事 | Python 中常见的表达 | 注意点 |
|---|---|---|
| 连接两个列表 | front + back | 会创建新列表 |
| 在现有列表后追加 | items.extend(values) | 会修改现有列表 |
| 读取一部分区间 | items[1:4] | 结束索引不包含在内 |
| 删除一部分区间 | del items[1:4] | 会修改现有列表 |
| 替换一部分区间 | items[1:4] = values | 即使长度不同也能替换 |
| 把字符串列表合成一个字符串 | " ".join(words) | join() 是字符串方法 |
在这一节里,不需要把这些语法全部背下来。只要记住:Python 列表并不只是通过有名字的函数来处理,很多时候也会通过序列语法来连接、切割和修改。
列表一开始创建的基本模式¶
一般来说,说“初始化(initialize)某个数据结构”,就是指第一次创建这个结构。在 Python 中,列表的起始方式会因为:值是不是已经知道、是不是要以后再填、是不是先用同一个值把位置占住,而有所不同。同时也要记住,列表是可变值。
概括起来,开始一个列表可以分成三个问题:值已经知道了吗?以后再填吗?还是先用同一个值把位置占出来?
已经知道值的时候¶
如果一开始就知道要放进去的值,就把它们写进方括号([])里。
问题场景:我想一次看到当值已经知道时,几种不同类型列表的创建例子。 输入(input):分数列表、标签列表、布尔值列表。 期望输出(output):分别打印三个列表。 要确认的概念:列表可以直接初始化数字、字符串、布尔值等不同种类的值集合。
这种方式在制作学习示例或小型设置列表时,最直接地显示出值的构成。
从空列表开始的时候¶
如果现在还没有值,但打算以后再慢慢放进去,就可以从空列表开始。
问题场景:我想确认一个基本模式:先用空列表开始,之后再一个个加入值。 输入(input):空列表 passed_scores 和两次 append。 期望输出(output):包含已添加值的列表。 要确认的概念:空列表经常被当作以后积累结果的起点。
这个例子说明:列表创建之后,仍然可以继续添加值。在真实的数据处理中,经常会使用迭代(loop)把符合条件的值收集进一个空列表。这个模式会在 P2-8.4 中再次出现。
用相同值先填出长度的时候¶
有时你已经知道所需长度,并希望先用相同的值把它填满。
问题场景:我想看一个例子:快速做出长度固定、默认值相同的列表。 输入(input):默认值 0 和重复次数 5。 期望输出(output):一个包含五个 0 的列表。 要确认的概念:[值] * 个数 可以用来快速创建简单的初始值列表。
这段代码会生成 [0, 0, 0, 0, 0]。不过,这种方式对于数字或字符串这种简单值很好理解,但如果在列表里放列表,就要特别小心。
问题场景:我想确认为什么看起来像“复制了多个相同内层列表”的代码其实很危险。 输入(input):rows = [[]] * 3,以及在第一个内层列表里追加 "A"。 期望输出(output):一个看起来像所有内层列表都一起变化了的结果。 要确认的概念:在嵌套列表里,多次指向同一个对象的初始化方式会造成意料之外的共享。
这段代码的结果可能和你期待的不一样。因为里面的列表并不是分别新建出来的,而是同一个列表被多次指向。在这一节里,我们先立下一个标准:嵌套列表不要用这种方式创建。
通过重复规则创建新列表的时候¶
另外,也经常会出现一种情况:把已有的值一个个处理,然后生成一个新列表。不过这更属于迭代结构的主题,而不是列表本身。本节只留下一个感觉:需要一个新的结果列表来装东西,而真正的迭代模式会在 P2-8.4 中处理。
本节按下面这个标准来选择列表的起始形状。
| 情况 | 初始化模式 |
|---|---|
| 值已经知道 | scores = [82, 75, 91] |
| 以后再追加值 | results = [] |
| 用相同简单值填满 | predictions = [0] * 5 |
| 按重复规则生成新列表 | P2-8.4 里的 for 与列表推导式 |
列表会出现在哪些场景¶
当同一目的或同一语境的值按顺序聚集在一起,并且位置或顺序本身有意义时,就会使用列表。
多个分数¶
问题场景:我想看一个最基本的例子:用一个分数列表来计算多个汇总值。 输入(input):分数列表 scores。 期望输出(output):最大值、最小值和平均值的计算结果。 要确认的概念:列表可以一次收集多个数字值,并作为汇总计算的输入。
分数列表既可以有顺序,也可以把整个集合拿来计算平均值。
多个句子¶
问题场景:我想看一个例子:按同一种方式逐个处理多个句子。 输入(input):包含三句话的列表 texts。 期望输出(output):每句话会在循环中依次打印出来。 要确认的概念:列表很适合按顺序遍历多个同类型项,比如文本。
在 LLM 或文本分类实践里,经常会看到句子列表。
多个模型输出¶
问题场景:我想看一个例子:逐个判断多个概率分数是否达到标准。 输入(input):概率列表 probabilities 和阈值 0.8。 期望输出(output):每个分数都会打印出 high confidence 或 check。 要确认的概念:列表可以按顺序评价模型的多个输出值。
如果模型针对多个输入给出了概率分数(probability score),这些结果也可以被看作一个列表。
多个文件名¶
问题场景:我想看一个最简单的例子:用同一种流程处理多个文件名。 输入(input):包含 train.csv、valid.csv、test.csv 的列表。 期望输出(output):每个文件名依次打印出来。 要确认的概念:列表适合按顺序列出多个同类型工作对象。
在项目实践中,经常需要用同一种方式处理多个文件。
用案例来看¶
案例 1. 如果要一次处理多个预测分数,需要什么结构¶
假设一个模型为五个样本给出了五个概率分数。人一开始可能还可以一个个地看 0.92、0.31、0.77 这些值,但很快就会出现需求:我想按顺序处理整个结果、我想只重新看第三个结果。
这时,如果把值写成 score1、score2、score3 这种分散变量,管理起来会很快变得不方便。很难用同一个标准去处理多个有顺序的值,迭代和局部选择也会变得麻烦。
列表正是适合这种场景的结构。像分数、句子、文件名这样的值,只要它们属于同一目的,而且顺序有意义,一旦用列表收集起来,就很容易通过索引取值、在末尾追加新结果,或者生成新的列表。
可确认的结果会直接体现在索引上。如果能通过 probabilities[2] 立即查看第三个值,也能通过 append() 在后面接上新结果,那这就是比起逐个命名变量更适合使用列表的场景。
检查清单¶
- 能把列表解释成
有顺序的值集合吗? - 能读懂
scores[0]和scores[-1]吗? - 能说明为什么把列表和 NumPy 数组当成同一个词会有风险吗?
- 能说出同一个列表可以被两个名字同时指向吗?
- 能把列表(list)解释成有顺序的值集合。
- 能说明
scores[0]、scores[-1]的含义。 - 能区分“带已知值开始的列表”“空列表”“用相同值填满的列表”。
- 能读懂通过
append()追加值的流程。 - 能大致区分
+、extend()、切片(slice)、del、切片赋值的差异。 - 能说明
join()不是列表方法,而是字符串(str)方法。 - 能说明 Python 列表里没有 JavaScript 式的
splice()方法,而相近工作会通过del、insert()、切片赋值来表达。 - 能说明同一个列表可能被多个名字指向。
- 能说明用重复同一值的方式创建嵌套列表时需要小心。
- 能先区分当前问题是不是在看顺序、索引或可变性吗?
来源与参考资料¶
- Python Software Foundation, Data Structures, Python 3.14.6 documentation,确认日期:2026-07-20。用于确认列表方法、把列表当作 stack 使用的例子、列表推导式与嵌套列表示例。
- Python Software Foundation, Built-in Types, Python 3.14.6 documentation,确认日期:2026-07-20。用于确认序列类型、mutable sequence 操作、索引与切片行为。
- Python Software Foundation, array — Efficient arrays of numeric values, Python 3.14.6 documentation,确认日期:2026-07-20。用于确认标准库
array会高效存储相同基本类型的值。 - NumPy Developers, NumPy: the absolute basics for beginners, NumPy v2.5 Manual,确认日期:2026-07-20。用于确认 NumPy 数组不同于普通 Python 列表,是高效处理大量数值数据的核心结构。