
文章目录
- 📖 开篇导读
- 🎯 学习目标
- 📚 知识点理论精讲
-
- 一、列表的定义与特性
-
- 1.1 什么是列表
- 1.2 列表的核心特性
- 1.3 列表的创建方式
- 二、列表的常用操作
-
- 2.1 访问元素:索引与切片
- 2.2 修改元素
- 2.3 添加元素
- 2.4 删除元素
- 2.5 查询与统计
- 2.6 排序与反转
- 2.7 复制列表:浅拷贝与深拷贝
-
- 浅拷贝:只复制第一层,内部嵌套的对象还是引用
- 深拷贝:递归复制所有层级,完全独立
- 三、遍历列表的多种方式
-
- 3.1 直接遍历元素
- 3.2 遍历索引(使用range和len)
- 3.3 同时遍历索引和元素(enumerate)
- 3.4 并行遍历多个列表(zip)
- 3.5 倒序遍历
- 四、列表推导式(List Comprehension)
-
- 4.1 基本语法
- 4.2 基础示例
- 4.3 嵌套循环的列表推导
- 4.4 条件表达式(三元)结合
- 4.5 列表推导式 vs map/filter
- 五、嵌套列表(多维列表)
-
- 5.1 创建二维列表
- 5.2 访问和修改嵌套列表
- 5.3 应用:矩阵转置
- 六、列表的高级技巧与性能
-
- 6.1 使用`*`重复列表的陷阱
- 6.2 列表作为栈和队列
- 6.3 列表的内存动态分配
- 💻 代码案例实操
-
- 案例1:待办事项管理器(增删改查综合)
- 案例2:列表排序与筛选——学生成绩处理
- 案例3:列表推导式——数据转换与过滤
- 案例4:深浅拷贝深度剖析
- 案例5:嵌套列表操作——矩阵运算
- 案例6:在遍历列表时删除元素的正确姿势
- ⚠️ 易错点避坑总结
- 📝 课后实战练习题
-
-
- 第1题:列表基础操作
- 第2题:列表方法练习
- 第3题:购物车系统
- 第4题:矩阵转置与翻转
- 第5题:列表推导式高级练习
- 第6题:深拷贝与浅拷贝实验
- 第7题:约瑟夫环问题(经典算法)
-
- 🔜 下节课预告
-
- 第9课:元组Tuple与字典Dict底层原理及实战用法
- 🔗《50节课 Python 从入门到精通》系列课程导航
📖 开篇导读
前几节课我们学习了字符串——一种存储字符序列的数据类型。但字符串只能存放字符,而且不可变。在实际开发中,我们经常需要处理一组数据:比如一个班级的学生姓名列表、一周的气温记录、待办事项清单……这些数据可能包含不同类型(整数、浮点数、字符串甚至其他列表),并且需要随时增删改查。
这时就需要列表。列表是Python中最灵活、最常用的容器类型,它可以存放任意类型的数据,并且可变(可以随时修改)。几乎任何需要处理“一组数据”的场景,列表都是首选。
💡 工作场景:读取CSV文件的一行数据,存在列表里;爬虫抓取的网页标题列表;数据库查询结果的每一行;用户上传的多个文件路径;机器学习中的特征向量……列表无处不在。
这一课,我们将系统学习列表的所有核心知识点:创建、索引、切片、常用方法、遍历方式、列表推导式、嵌套列表,以及深浅拷贝的区别。学完本课,你将能自如地管理任何集合数据。
🎯 学习目标
| 1️⃣ | 掌握列表的定义、特性(可变、有序、可重复) | 理解列表与元组、集合的区别 |
| 2️⃣ | 熟练使用增删改查方法(append、insert、remove、pop等) | 日常数据操作 |
| 3️⃣ | 掌握列表切片和遍历的多种方式 | 批量处理数据 |
| 4️⃣ | 理解列表推导式,能写出简洁高效的代码 | 面试高频,替代map/filter |
| 5️⃣ | 掌握嵌套列表的创建与访问 | 处理矩阵、表格数据 |
| 6️⃣ | 区分浅拷贝与深拷贝,理解其底层原理 | 防止共享引用导致的bug |
🔥 面试考点:面试官常问“列表和元组的区别?”“列表的append和extend区别?”“如何在遍历列表时删除元素?”“列表推导式与生成器表达式的区别?”“深浅拷贝的实现方式?”
📚 知识点理论精讲
一、列表的定义与特性
1.1 什么是列表
列表是Python内置的可变序列,用方括号[]表示,元素之间用逗号分隔。
# 空列表
empty = []
# 同类型元素
numbers = [1, 2, 3, 4, 5]
fruits = ["苹果", "香蕉", "橙子"]
# 混合类型(Python允许,但通常不建议)
mixed = [1, "hello", 3.14, True]
# 列表可以嵌套
matrix = [[1, 2], [3, 4]]
🧠 通俗类比:列表就像一个可伸缩的置物架——你可以往上面放任何东西(元素),东西有顺序,可以随时拿掉、替换、增加新的,架子的大小可以动态变化。
1.2 列表的核心特性
| 有序 | 元素有固定的位置,可以通过索引访问 | [1,2,3]和[2,1,3]是不同的列表 |
| 可变 | 可以修改、增加、删除元素 | lst[0]=100 |
| 可重复 | 元素可以重复出现 | [1,1,2]合法 |
| 异构 | 可以存放不同类型的元素 | [1, "a"]合法 |
| 动态长度 | 长度可以随时变化 | append、pop等 |
1.3 列表的创建方式
# 方式1:方括号
lst1 = [1, 2, 3]
# 方式2:list()构造器(从可迭代对象创建)
lst2 = list("hello") # ['h','e','l','l','o']
lst3 = list(range(5)) # [0,1,2,3,4]
# 方式3:列表推导式(后面详解)
squares = [x**2 for x in range(10)]
# 方式4:重复运算符
zeros = [0] * 5 # [0,0,0,0,0]
二、列表的常用操作
2.1 访问元素:索引与切片
列表的索引和切片规则与字符串完全相同(正索引、负索引、左闭右开)。
fruits = ["apple", "banana", "cherry", "durian", "elderberry"]
# 索引
print(fruits[0]) # apple
print(fruits[–1]) # elderberry
print(fruits[2]) # cherry
# 切片(返回新列表)
print(fruits[1:4]) # ['banana', 'cherry', 'durian']
print(fruits[:3]) # ['apple', 'banana', 'cherry']
print(fruits[::2]) # ['apple', 'cherry', 'elderberry']
print(fruits[::–1]) # 反转列表
📌 工作应用:切片常用于分页、获取子集。
2.2 修改元素
直接通过索引赋值即可修改。
nums = [10, 20, 30]
nums[1] = 25
print(nums) # [10, 25, 30]
# 切片赋值(可以同时修改多个元素,甚至改变长度)
nums[0:2] = [100, 200, 300] # 替换前两个元素为三个新元素
print(nums) # [100, 200, 300, 30]
2.3 添加元素
| append(x) | 在列表末尾添加一个元素 | lst.append(4) |
| insert(i, x) | 在索引i处插入元素x | lst.insert(0, 'start') |
| extend(iterable) | 将可迭代对象的所有元素追加到末尾 | lst.extend([4,5]) |
tasks = ["写报告", "开会"]
# append:加一个元素
tasks.append("回复邮件")
print(tasks) # ['写报告', '开会', '回复邮件']
# insert:在指定位置插入
tasks.insert(1, "吃午饭")
print(tasks) # ['写报告', '吃午饭', '开会', '回复邮件']
# extend:合并另一个列表
new_tasks = ["检查代码", "提交PR"]
tasks.extend(new_tasks)
print(tasks) # ['写报告', '吃午饭', '开会', '回复邮件', '检查代码', '提交PR']
💡 面试考点:问“append和extend的区别?”答:append将参数作为一个元素添加;extend将可迭代对象的每个元素分别添加。
2.4 删除元素
| remove(x) | 删除第一个值为x的元素,不存在则报错 | None |
| pop(i=-1) | 删除并返回索引i处的元素(默认最后一个) | 被删除的元素 |
| clear() | 清空列表所有元素 | None |
| del lst[i] | 删除索引i的元素(或切片) | 无(语句) |
cart = ["苹果", "香蕉", "橙子", "苹果"]
# remove:按值删除第一个匹配
cart.remove("苹果") # 删除了第一个苹果
print(cart) # ['香蕉', '橙子', '苹果']
# pop:按索引删除并返回
item = cart.pop(1) # 删除索引1的"橙子"
print(item) # 橙子
print(cart) # ['香蕉', '苹果']
cart.pop() # 删除最后一个
print(cart) # ['香蕉']
# clear:清空
cart.clear()
print(cart) # []
# del语句
nums = [1, 2, 3, 4, 5]
del nums[2] # 删除索引2的元素
print(nums) # [1, 2, 4, 5]
del nums[0:2] # 删除切片
print(nums) # [5]
⚠️ 高频坑点:remove删除的是第一个匹配的值,如果要删除所有匹配值,需要循环或列表推导。pop不传参数时删除最后一个,比pop(0)快(因为删除开头需要移动后面所有元素)。
2.5 查询与统计
| index(x, start, end) | 返回第一个x的索引,不存在则报错 | int |
| count(x) | 统计x出现的次数 | int |
| len(lst) | 返回列表长度 | int |
| x in lst | 判断x是否在列表中 | bool |
scores = [85, 92, 78, 92, 88]
print(scores.index(92)) # 1(第一次出现的位置)
# print(scores.index(100)) # ValueError
print(scores.count(92)) # 2
print(len(scores)) # 5
print(85 in scores) # True
print(100 not in scores) # True
# index可以指定搜索范围
print(scores.index(92, 2)) # 从索引2开始找:返回3
2.6 排序与反转
| list.sort(key=None, reverse=False) | 原地排序,修改原列表 | 返回None |
| sorted(list, …) | 返回新列表,原列表不变 | 内置函数 |
| list.reverse() | 原地反转 | 返回None |
| list[::-1] | 切片反转,返回新列表 | 不修改原列表 |
nums = [3, 1, 4, 1, 5, 9]
# 原地排序(升序)
nums.sort()
print(nums) # [1, 1, 3, 4, 5, 9]
# 降序
nums.sort(reverse=True)
print(nums) # [9, 5, 4, 3, 1, 1]
# 使用sorted返回新列表
original = [3, 2, 1]
sorted_new = sorted(original)
print(original) # [3, 2, 1] 不变
print(sorted_new) # [1, 2, 3]
# 反转
nums = [1, 2, 3]
nums.reverse()
print(nums) # [3, 2, 1]
# 切片反转(不修改原列表)
new_nums = nums[::–1]
💡 工作应用:sort的key参数可以指定排序依据,比如按字符串长度排序:lst.sort(key=len),按第二个元素排序:lst.sort(key=lambda x: x[1])。
2.7 复制列表:浅拷贝与深拷贝
这是列表操作中最容易出错的点之一。
浅拷贝:只复制第一层,内部嵌套的对象还是引用
# 浅拷贝的几种方式
original = [1, 2, [3, 4]]
copy1 = original[:] # 切片
copy2 = list(original) # 构造器
copy3 = original.copy() # copy方法
import copy; copy4 = copy.copy(original) # copy模块
# 修改浅拷贝的外层元素不影响原列表
copy1[0] = 100
print(original[0]) # 1(不变)
# 但是修改内层可变对象会影响原列表
copy1[2][0] = 99
print(original[2]) # [99, 4](被改了!)
深拷贝:递归复制所有层级,完全独立
import copy
original = [1, 2, [3, 4]]
deep = copy.deepcopy(original)
deep[2][0] = 999
print(original[2]) # [3, 4] 不受影响
🔥 面试考点:“列表的浅拷贝和深拷贝区别?如何实现?”答:浅拷贝只复制引用,深拷贝递归复制所有内容。用copy.copy()和copy.deepcopy()。
三、遍历列表的多种方式
3.1 直接遍历元素
fruits = ["apple", "banana", "cherry"]
for fruit in fruits:
print(fruit)
3.2 遍历索引(使用range和len)
for i in range(len(fruits)):
print(f"索引{i}: {fruits[i]}")
3.3 同时遍历索引和元素(enumerate)
for i, fruit in enumerate(fruits):
print(f"{i}: {fruit}")
# 可以指定起始索引
for i, fruit in enumerate(fruits, start=1):
print(f"{i}: {fruit}")
3.4 并行遍历多个列表(zip)
names = ["张三", "李四", "王五"]
ages = [25, 30, 28]
for name, age in zip(names, ages):
print(f"{name} {age}岁")
3.5 倒序遍历
for fruit in reversed(fruits):
print(fruit)
# 或者用切片
for fruit in fruits[::–1]:
print(fruit)
四、列表推导式(List Comprehension)
列表推导式是Python独有的函数式编程特性,能够用一行简洁的代码生成新列表。
4.1 基本语法
[表达式 for 变量 in 可迭代对象 if 条件]
4.2 基础示例
# 传统方式
squares = []
for i in range(10):
squares.append(i**2)
# 列表推导式
squares = [i**2 for i in range(10)]
# 带条件:只保留偶数平方
even_squares = [i**2 for i in range(10) if i % 2 == 0]
print(even_squares) # [0, 4, 16, 36, 64]
4.3 嵌套循环的列表推导
# 生成坐标对
coords = [(x, y) for x in range(3) for y in range(2)]
print(coords) # [(0,0),(0,1),(1,0),(1,1),(2,0),(2,1)]
# 等价于:
coords = []
for x in range(3):
for y in range(2):
coords.append((x, y))
4.4 条件表达式(三元)结合
# 对列表中的数字,偶数保留,奇数变为0
nums = [1, 2, 3, 4, 5]
result = [x if x % 2 == 0 else 0 for x in nums]
print(result) # [0, 2, 0, 4, 0]
4.5 列表推导式 vs map/filter
# map: 对每个元素应用函数
nums = [1, 2, 3, 4]
squares_map = list(map(lambda x: x**2, nums))
# 列表推导更可读
squares_comp = [x**2 for x in nums]
# filter: 筛选元素
even_filter = list(filter(lambda x: x % 2 == 0, nums))
even_comp = [x for x in nums if x % 2 == 0]
💡 工作应用:列表推导式简洁、性能通常优于手动循环,但不建议过于复杂(嵌套超过两层或包含复杂逻辑时,还是用普通循环可读性更好)。
五、嵌套列表(多维列表)
列表中的元素可以是列表,形成多维结构。
5.1 创建二维列表
# 3行4列的矩阵(全0)
matrix = [[0 for _ in range(4)] for _ in range(3)]
# 注意:错误的创建方式(共享引用)
bad_matrix = [[0] * 4] * 3 # 三行引用同一个列表!
bad_matrix[0][0] = 1
print(bad_matrix) # [[1,0,0,0], [1,0,0,0], [1,0,0,0]] 一起变了
⚠️ 高频坑点:用[[0]*4]*3创建二维列表时,内层列表是同一个对象的引用,修改一个会影响所有行。正确做法用列表推导:[[0]*4 for _ in range(3)]。
5.2 访问和修改嵌套列表
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
print(matrix[0][1]) # 2(第0行第1列)
matrix[1][2] = 100 # 修改第二行第三列
print(matrix) # [[1,2,3],[4,5,100],[7,8,9]]
# 遍历二维列表
for row in matrix:
for elem in row:
print(elem, end=" ")
print()
5.3 应用:矩阵转置
matrix = [[1,2,3], [4,5,6]]
# 转置为3行2列
transpose = [[matrix[j][i] for j in range(len(matrix))] for i in range(len(matrix[0]))]
print(transpose) # [[1,4],[2,5],[3,6]]
六、列表的高级技巧与性能
6.1 使用*重复列表的陷阱
# 对一维列表,元素是不可变类型时没问题
a = [0] * 5 # [0,0,0,0,0]
a[0] = 1 # 独立修改,没问题
# 但如果列表元素是可变对象,则所有元素引用同一个对象
b = [ [0] ] * 3 # [[0], [0], [0]]
b[0][0] = 1
print(b) # [[1],[1],[1]] —— 全部变了
6.2 列表作为栈和队列
- 栈(LIFO后进先出):append压栈,pop()弹栈。
- 队列(FIFO先进先出):append入队,pop(0)出队(但效率低,可用collections.deque)。
# 栈
stack = []
stack.append(1)
stack.append(2)
stack.pop() # 2
# 队列(不推荐用列表,效率低)
from collections import deque
q = deque([1,2,3])
q.append(4)
q.popleft() # 1
6.3 列表的内存动态分配
列表是动态数组,当容量不足时,Python会分配更大的内存(通常是当前容量的1.125倍左右),复制元素到新内存。频繁的append会有少量开销,但总体仍是O(1)均摊。
💻 代码案例实操
案例1:待办事项管理器(增删改查综合)
"""
todo_manager.py
一个简单的命令行待办事项管理器,演示列表增删改查
"""
todos = []
def show_menu():
print("\\n===== 待办事项管理器 =====")
print("1. 查看所有待办")
print("2. 添加待办")
print("3. 删除待办")
print("4. 修改待办")
print("5. 退出")
def show_todos():
if not todos:
print("暂无待办事项")
return
print("\\n当前待办列表:")
for i, todo in enumerate(todos, 1):
print(f"{i}. {todo}")
def add_todo():
todo = input("请输入待办内容:").strip()
if todo:
todos.append(todo)
print(f"已添加:{todo}")
else:
print("内容不能为空")
def delete_todo():
show_todos()
if not todos:
return
try:
idx = int(input("请输入要删除的序号:")) – 1
if 0 <= idx < len(todos):
removed = todos.pop(idx)
print(f"已删除:{removed}")
else:
print("序号无效")
except ValueError:
print("请输入数字")
def update_todo():
show_todos()
if not todos:
return
try:
idx = int(input("请输入要修改的序号:")) – 1
if 0 <= idx < len(todos):
new_content = input("请输入新内容:").strip()
if new_content:
old = todos[idx]
todos[idx] = new_content
print(f"已修改:{old} -> {new_content}")
else:
print("内容不能为空")
else:
print("序号无效")
except ValueError:
print("请输入数字")
while True:
show_menu()
choice = input("请选择操作(1-5): ")
if choice == '1':
show_todos()
elif choice == '2':
add_todo()
elif choice == '3':
delete_todo()
elif choice == '4':
update_todo()
elif choice == '5':
print("感谢使用,再见!")
break
else:
print("无效选项,请重新输入")
案例2:列表排序与筛选——学生成绩处理
"""
grade_processor.py
对学生成绩列表进行各种操作
"""
# 原始成绩(姓名,分数)
students = [
("张三", 85),
("李四", 92),
("王五", 78),
("赵六", 60),
("周七", 45)
]
# 1. 按分数升序排序
students_sorted = sorted(students, key=lambda x: x[1])
print("按分数升序:", students_sorted)
# 2. 按分数降序(前三名)
students_desc = sorted(students, key=lambda x: x[1], reverse=True)
top3 = students_desc[:3]
print("前三名:", top3)
# 3. 筛选出及格(>=60)的学生
passed = [s for s in students if s[1] >= 60]
print("及格名单:", passed)
# 4. 计算平均分
avg_score = sum(s[1] for s in students) / len(students)
print(f"平均分: {avg_score:.2f}")
# 5. 找出最高分和最低分
max_student = max(students, key=lambda x: x[1])
min_student = min(students, key=lambda x: x[1])
print(f"最高分: {max_student[0]} ({max_student[1]})")
print(f"最低分: {min_student[0]} ({min_student[1]})")
# 6. 统计各分数段人数
segments = [0, 0, 0, 0, 0] # <60, 60-69, 70-79, 80-89, >=90
for _, score in students:
if score < 60:
segments[0] += 1
elif score < 70:
segments[1] += 1
elif score < 80:
segments[2] += 1
elif score < 90:
segments[3] += 1
else:
segments[4] += 1
print(f"分布: <60:{segments[0]}, 60-69:{segments[1]}, 70-79:{segments[2]}, 80-89:{segments[3]}, ≥90:{segments[4]}")
案例3:列表推导式——数据转换与过滤
"""
list_comprehension_demo.py
列表推导式的多种实战场景
"""
# 1. 提取列表中所有偶数
nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = [x for x in nums if x % 2 == 0]
print("偶数:", evens)
# 2. 字符串列表转大写
words = ["hello", "world", "python"]
upper_words = [w.upper() for w in words]
print("大写:", upper_words)
# 3. 扁平化嵌套列表(两层)
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flatten = [num for row in matrix for num in row]
print("扁平化:", flatten)
# 4. 过滤掉空字符串
data = ["a", "", "b", None, "c", " "]
clean = [s for s in data if s and s.strip()]
print("非空:", clean)
# 5. 带条件表达式的
numbers = [1, 2, 3, 4, 5]
label = ["偶数" if n % 2 == 0 else "奇数" for n in numbers]
print("标签:", label)
# 6. 使用集合去重(保留顺序)
original = [1, 2, 2, 3, 1, 4]
seen = set()
unique = [x for x in original if not (x in seen or seen.add(x))]
print("去重保留顺序:", unique)
案例4:深浅拷贝深度剖析
"""
shallow_deep_copy.py
演示深浅拷贝的区别及实际影响
"""
import copy
print("=== 浅拷贝演示 ===")
original = [1, 2, [3, 4]]
shallow = original.copy()
print("修改浅拷贝的外层元素(不可变)")
shallow[0] = 100
print(f"original: {original}") # [1, 2, [3, 4]] 不变
print(f"shallow: {shallow}") # [100, 2, [3, 4]]
print("\\n修改浅拷贝的内层列表(可变)")
shallow[2][0] = 999
print(f"original: {original}") # [1, 2, [999, 4]] 被影响!
print(f"shallow: {shallow}") # [100, 2, [999, 4]]
print("\\n=== 深拷贝 ===")
original2 = [1, 2, [3, 4]]
deep = copy.deepcopy(original2)
deep[2][0] = 888
print(f"original2: {original2}") # [1, 2, [3, 4]] 不变
print(f"deep: {deep}") # [1, 2, [888, 4]]
# 实际工作场景:配置数据的独立副本
base_config = {"host": "localhost", "ports": [8000, 8001]}
# 如果不希望函数修改原配置,传入深拷贝
def modify_config(cfg):
cfg["ports"].append(8002)
return cfg
new_config = modify_config(copy.deepcopy(base_config))
print("\\n原配置 ports:", base_config["ports"]) # [8000, 8001]
print("新配置 ports:", new_config["ports"]) # [8000, 8001, 8002]
案例5:嵌套列表操作——矩阵运算
"""
matrix_operations.py
实现矩阵加法、乘法等运算
"""
def create_matrix(rows, cols, init=0):
"""创建指定行列的矩阵(使用列表推导避免共享引用)"""
return [[init for _ in range(cols)] for _ in range(rows)]
def print_matrix(matrix):
for row in matrix:
print(" ".join(f"{x:4}" for x in row))
def matrix_add(A, B):
"""矩阵加法(要求同形)"""
rows, cols = len(A), len(A[0])
result = create_matrix(rows, cols)
for i in range(rows):
for j in range(cols):
result[i][j] = A[i][j] + B[i][j]
return result
def matrix_multiply(A, B):
"""矩阵乘法:A(m×n) * B(n×p) = C(m×p)"""
m, n = len(A), len(A[0])
p = len(B[0])
result = create_matrix(m, p)
for i in range(m):
for j in range(p):
total = 0
for k in range(n):
total += A[i][k] * B[k][j]
result[i][j] = total
return result
# 示例
A = [[1, 2], [3, 4]]
B = [[5, 6], [7, 8]]
print("矩阵 A:")
print_matrix(A)
print("\\n矩阵 B:")
print_matrix(B)
C = matrix_add(A, B)
print("\\nA + B:")
print_matrix(C)
D = matrix_multiply(A, B)
print("\\nA * B:")
print_matrix(D)
案例6:在遍历列表时删除元素的正确姿势
"""
delete_while_iterating.py
演示遍历列表时删除元素的常见错误及正确方法
"""
# 错误示例:遍历时直接删除会导致跳过元素
numbers = [1, 2, 3, 4, 5, 6]
for n in numbers:
if n % 2 == 0:
numbers.remove(n) # 删除偶数
print("错误结果:", numbers) # [1, 3, 5] 看起来对了,但若列表是[1,2,2,3]会出问题
# 正确方法1:遍历副本(切片)
numbers = [1, 2, 3, 4, 5, 6]
for n in numbers[:]:
if n % 2 == 0:
numbers.remove(n)
print("方法1(副本):", numbers)
# 正确方法2:倒序遍历,从后向前删除
numbers = [1, 2, 3, 4, 5, 6]
for i in range(len(numbers)–1, –1, –1):
if numbers[i] % 2 == 0:
del numbers[i]
print("方法2(倒序):", numbers)
# 正确方法3:列表推导式(推荐,创建新列表)
numbers = [1, 2, 3, 4, 5, 6]
numbers = [n for n in numbers if n % 2 != 0]
print("方法3(推导):", numbers)
# 正确方法4:filter函数
numbers = [1, 2, 3, 4, 5, 6]
numbers = list(filter(lambda n: n % 2 != 0, numbers))
print("方法4(filter):", numbers)
⚠️ 易错点避坑总结
| 1 | 使用[[0]*3]*4创建多维列表 | 内层列表共享引用,修改一个会变所有 | 用列表推导[[0]*3 for _ in range(4)] |
| 2 | 遍历列表时直接删除元素 | 跳过元素或索引错误 | 遍历副本、倒序遍历或用列表推导 |
| 3 | 误用append添加多个元素 | lst.append([a,b])会添加嵌套列表 | 用extend或+= |
| 4 | 浅拷贝后修改内层可变对象影响原列表 | 意想不到的bug | 用深拷贝copy.deepcopy() |
| 5 | index找不到元素时未处理异常 | 程序崩溃 | 先用in判断或try/except |
| 6 | pop(0)频繁使用 | 时间复杂度O(n),效率低 | 用collections.deque |
| 7 | 列表作为函数默认参数 | def f(lst=[])多次调用共享列表 | 默认参数设为None |
| 8 | sort和sorted混淆 | 忘记sorted返回新列表 | 记住:sort原地,sorted新建 |
| 9 | remove只删除第一个匹配值 | 需要删除所有匹配时漏删 | 用循环或列表推导过滤 |
| 10 | 混淆+和extend | +返回新列表,extend修改原列表 | 根据需求选择 |
📝 课后实战练习题
第1题:列表基础操作
创建一个包含10个随机整数的列表(范围1-100)。完成:
第2题:列表方法练习
已知两个列表:list1 = [1, 2, 3, 4, 5] 和 list2 = [4, 5, 6, 7, 8],写出代码:
第3题:购物车系统
模拟一个简单的购物车,要求如下:
- 初始购物车为空字典(商品名:价格),但请用两个平行列表(names, prices)存储。
- 提供菜单:添加商品、删除商品、修改数量(价格)、查看购物车、结账(计算总价)。
- 使用列表的相关方法实现。
第4题:矩阵转置与翻转
给定一个二维列表(3×4):
matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12]
]
要求:
第5题:列表推导式高级练习
给定列表 words = ["apple", "banana", "cherry", "date", "elderberry", "fig"],使用列表推导式完成:
第6题:深拷贝与浅拷贝实验
创建列表 original = [1, [2, 3], [4, 5]],分别进行赋值、浅拷贝、深拷贝三种操作。然后修改original[1][0] = 99,观察三个副本的变化,并解释原因。编写代码验证。
第7题:约瑟夫环问题(经典算法)
有n个人围成一圈,从第一个人开始报数,数到m的人出列,然后从下一个人继续报数,直到所有人出列。用列表模拟这个过程,输出出列顺序。例如n=5, m=3,输出应为[3,1,5,2,4]。
🔜 下节课预告
列表是可变序列,元组是不可变序列;字典是键值对映射。下节课我们将深入剖析元组和字典。
第9课:元组Tuple与字典Dict底层原理及实战用法
内容包括:
- 元组的定义、特性和不可变性
- 元组的打包与解包
- 字典的底层哈希表原理
- 字典常用操作(增删改查、遍历)
- 字典推导式
- 元组与列表的选择场景
- 实战:词频统计、电话本系统
元组和字典是Python数据结构的另外两块重要拼图,掌握它们你将能应对更多复杂数据组织需求。
🌟 学习鼓励:列表是Python中最常用的数据结构,它的灵活性让数据处理变得轻松。但正因为灵活,也容易出错(尤其是浅拷贝和遍历删除)。建议你把文中的案例逐一运行,修改参数观察效果,亲手踩坑才能印象深刻。继续加油!
🔗《50节课 Python 从入门到精通》系列课程导航
去订阅
🌟 感谢您耐心阅读到这里! 💡 如果本文对您有所启发欢迎: 👍 点赞📌 收藏 📤 分享给更多需要的伙伴。 🗣️ 期待在评论区看到您的想法, 共同进步。 🔔 关注我,持续获取更多干货内容~ 🤗 我们下篇文章见~

