跳转至

6.1 数据类型进阶——列表

内容梗概

本课是"数据类型进阶"系列的第一部分,系统讲解列表(list)的进阶操作。老师将列表操作分为四大类:增加、更新、查找、其他(含删除),逐类结合交互模式和 VS Code 演示。重点强调了切片赋值(含步长切片赋值的限制)、sort() 等就地修改方法返回 None 的"坑"、insert/pop(0) 的效率问题,以及 copy 与完整切片的等价关系。最后用一个"选课名单"的综合例子把所有操作串起来演示了一遍。

知识点详解

列表进阶操作的四大分类(约 01:40)

  • 增加:向列表中添加内容
  • 更新:更改列表中已有的内容(与"增加"本质上都是对列表内容的变更)
  • 查找:定位某个元素、判断是否包含、统计次数等
  • 其他:删除、复制、弹出等

老师提醒(约 10:10):这些方法不用死记,工作多年的程序员也要查官方文档,用多了自然记住。

增加操作(约 02:23)

  • a += [新列表]:在列表末尾拼接一个新列表。
  • a *= n:把列表内容**重复 n 次**(约 02:53),如 [1,2,3] * 3 得到三个 1,2,3。
  • a.append(x)(约 04:06):在末尾追加**单个**元素;若传入列表,会把整个列表当作一个元素塞进去(产生嵌套列表)。
  • a.extend(t)(约 04:32):把可迭代对象 t 中的元素**逐个**取出追加到末尾,效果等价于 +=。注意 t 不一定是列表,任何可迭代对象(如元组)都可以(约 08:52)。
  • a.clear()(约 04:56):清空列表(老师称此处为"超纲知识",提前使用)。
  • a.insert(i, x)(约 05:48):在索引 i 处插入元素 x,其后所有元素索引顺移。
  • 效率问题(约 08:11):在列表前部插入会让后面所有元素后移,效率较低;处理复杂/大规模任务时要注意。

更新操作(约 10:47)

  • 切片赋值:a[start:end] = t,把 start 到 end 的部分替换为可迭代对象 t 的内容(约 11:05)。右侧 t 同样只需可迭代,不必是列表。
  • 无步长时:新内容长度**可以**与被替换区间长度不同,甚至可以是空列表(相当于删除这段元素)(约 13:04)。
  • 带步长的切片赋值:a[start:end:step] = t,两侧长度**必须完全一致**,否则报 ValueError(约 13:44–16:15,演示了"attempt to assign sequence of size 4 to extended slice of size 5"错误,并强调要学会读错误信息)。带步长时也不能用空列表删除元素,要用 del。
  • 排序 a.sort(key=None, reverse=False)(约 17:17):
  • 默认按元素值从小到大排序;reverse=True 则从大到小。
  • 大坑(约 18:36):sort() 就地修改**列表本身,**返回 None。d = c.sort() 只会让 d 变成 None。老师称去年出过考题。
  • append、extend、insert、reverse 等就地修改方法同样返回 None(约 19:48–22:26,逐一验证)。
  • a.reverse()(约 20:33):就地倒序,同样返回 None。

查找操作(约 22:38)

  • x in a / x not in a(约 22:50):判断元素是否在列表中,可直接用作 if 条件。演示用 VS Code 判断某人是否在名单中。
  • min(a) / max(a)(约 25:40):取最小/最大元素。
  • a.index(x[, start[, end]])(约 25:48):返回元素 x **第一次出现**的索引;可选 start/end 限定查找范围。
  • 文档中**方括号表示可选参数**(约 26:45),与命令行可选参数写法惯例一致。
  • 只返回第一次出现的下标;想找所有下标目前只能配合循环(约 30:05)。
  • 索引从 0 开始,给人看名次时要 +1。
  • a.count(x)(约 28:09):统计元素出现次数;**不能**直接指定范围,但可先切片再 count。老师举例:用打卡记录 count 统计出勤次数。

其他操作(约 30:39)

  • a.copy()(约 30:59):返回一个**新列表**,与完整切片 a[:] 等价;与前面方法不同,它**有返回值**(新列表)。对副本的操作不影响原列表。
  • b = a * n(约 32:24):把重复 n 次的结果存入新变量(与 *= 原地操作区分)。
  • a.pop([i])(约 33:20):不传参数弹出末尾元素;可传索引弹出指定位置元素。pop(0) 从头部取出会使后面所有元素前移,效率低,后续会讲更好的方式。
  • a.remove(x)(约 34:55):按**值**删除,只删**第一个**匹配项(与 pop 按下标删除区分)。
  • a.clear():清空列表,返回 None,不取出元素。
  • del a[i] / del a[start:end:step](约 36:17):删除指定部分;带步长的删除只能用 del,不能用空列表赋值。
  • del a(约 36:46):删除整个变量,之后引用会报 NameError: name 'a' is not defined——注意它不是 None,是变量本身没了。

示例与演示

  • 交互模式演示(约 03:06 起):a=[1,2,3]、b=[4,5,6],演示 +=、*=、append(10)、append 一个列表产生嵌套、clear 后 extend 恢复等。
  • 切片赋值实验(约 11:36):用列表推导式生成 a = [0..10],把 2,3,4(索引 2:5)替换为 [10,11,12];替换为空列表实现批量删除。用带步长切片 b[0::2] 把偶数位替换为 'a','b','c','d' 等字符;长度不匹配时报错。
  • in 判断(约 23:23):VS Code 中定义名单列表,用 if 名字 in 列表 判断某人是否在名单中。
  • 综合例子:选课名单(约 37:42 起,课件下方完整代码):
  • 用列表推导式生成 10 个假学号(20190001 起)作为初始选课名单;
  • append 单独新增一位,extend(range(20,30)) 批量新增一批(演示 extend 可直接接收 range);
  • insert(0, ...) 把学号全 0 的同学插到第一位;
  • 无步长切片替换 students[5:15]、带步长切片替换 students[0:5:2];
  • 加 print 提示语观察"替换前/替换后"(老师明确**不推荐单步调试**,推荐用 print 观察程序执行);
  • sort() 后 reverse() 实现学号从大到小(指出可合并为 sort(reverse=True));
  • in 判断某同学是否选上,remove 移除,clear 清空(与 students = [] 效果对比),最后 del students 后引用报错。
  • 插曲(约 42:09):print 中字符串与列表不能用 + 拼接(类型不同),改为 print 传多个参数用空格分隔。

重点与难点

  • sort() 等就地方法返回 None:不要写 d = c.sort();排序结果在 c 本身。
  • 带步长切片赋值两侧长度必须相等;无步长则不限。带步长删除必须用 del。
  • append(整体放入)与 extend(逐个取出)的区别。
  • insert、pop(0) 会引起元素整体移动,效率低。
  • remove 按值删且只删第一个;pop 按下标删;del 变量 会把变量本身删掉(再引用报 NameError)。
  • copy() 返回新列表(有返回值),与其他就地方法不同。
  • 官方文档中方括号 [start[, end]] 表示可选参数。
  • 建议用 print 而非单步调试观察程序执行过程。

关联内容

  • 前置知识:第 5 章序列基础(取值、切片、拼接)、列表推导式、lambda 匿名函数(讲 sort(key=...) 时回顾)。
  • 本课提到 extend 的参数可以是元组、range——分别在本章 6.2(元组与 range)详细展开;提到"从头部取元素的更好方式"留待后续课程。
  • "方法 vs 函数"的概念留待后续面向对象章节讲解(约 21:01)。
  • 与上周五作业及"直男表白"解码工具(字符串两两切分)呼应。