先想一个问题:你去超市买东西,是不是要拿一张购物单,一样一样往上记?程序里也有同样的需求——存一串数据:一个班的成绩、一购物车的商品、一页通讯录。存这一串东西的容器,就是今天的主角:列表。
昨天的字符串也是一串东西,但它是"文字",只能读不能改;列表是"盒子",能增、能删、能改。购物车、成绩单、待办清单……凡是"一串数据",都得用列表装。所以列表是本周的必会项,后面所有项目——不管是写通讯录还是做记账本——数据都要先装进列表,再靠循环逐个处理。今天学的增删改查,就是操作列表的四个基本动作。
列表长什么样:方括号装一串东西
列表用方括号 [] 包起来,里面的东西叫元素,用逗号隔开。先看四种典型写法:
fruits = ["苹果", "香蕉", "橙子"] # 3 个元素的列表
empty = [] # 空列表,先空着,以后往里加
nums = [1, 2, 3, 4, 5] # 数字列表
mixed = ["小明", 18, 92.5, True] # 列表里可以装不同类型(但一般不建议混装)
列表有两个关键特点,跟字符串正好一正一反:
| 特点 | 说明 | 例子 |
|---|---|---|
| 有序 | 元素有固定顺序,按下标取,下标从 0 开始(和字符串一样) | ["a", "b"][0] 是 a |
| 可改 | 列表里的元素能增、能删、能改(和字符串正好相反) | fruits[0] = "新东西" |
有序和字符串一样,所以昨天学的索引、切片、len(),列表全都能用:
fruits = ["苹果", "香蕉", "橙子"]
print(fruits) # ['苹果', '香蕉', '橙子']
print(fruits[0]) # 苹果(下标从 0 开始,和字符串一样)
print(fruits[-1]) # 橙子(负数从右往左数)
print(fruits[1:]) # ['香蕉', '橙子'](切片也适用!)
print(len(fruits)) # 3(列表长度 = 元素个数)
输出:
['苹果', '香蕉', '橙子']
苹果
橙子
['香蕉', '橙子']
3
区别只在于:字符串"只能看不能改",列表"能看也能改"。写列表注意三点:
- 用的是方括号
[],不是小括号(),也不是花括号{}——写错类型就变了。 - 元素之间用英文逗号隔开,中文逗号会让 Python 直接报
SyntaxError。 - 下标越界和字符串一样报错,报的是
IndexError: list index out of range。
查:看看列表里有什么
"查"有三种常用方式:按下标取单个、切片取一段、in 判断有没有。配上 len() 数个数:
fruits = ["苹果", "香蕉", "橙子"]
# 方式一:按下标取单个
print(fruits[1]) # 香蕉
# 方式二:in 判断在不在(结果一定是 True / False)
if "苹果" in fruits:
print("有苹果!")
else:
print("没有苹果")
# 方式三:len 数有几个
print(f"一共 {len(fruits)} 种水果")
输出:
香蕉
有苹果!
一共 3 种水果
两个小提醒:in 判断的是"有没有这个值",不是下标,所以 2 in fruits 的意思是"列表里有没有 2 这个元素";fruits[3] 在只有 3 个元素的列表里会报 IndexError,取之前先用 len() 确认。判断列表是不是空的,可以写 if len(fruits) == 0:,更地道的写法是直接 if fruits:——空列表在判断里等于 False。
增:往列表里加东西
加东西有两个方法,区别在加的位置:
| 方法 | 作用 | 例子 |
|---|---|---|
append(值) |
加到末尾(最常用) | fruits.append("葡萄") |
insert(位置, 值) |
插到指定位置(位置从 0 数) | fruits.insert(0, "西瓜") |
fruits = ["苹果", "香蕉"]
fruits.append("橙子") # 加在末尾
print(fruits) # ['苹果', '香蕉', '橙子']
fruits.insert(0, "西瓜") # 插到第 0 个位置
print(fruits) # ['西瓜', '苹果', '香蕉', '橙子']
append 配循环,就是购物车的雏形——从用户手里收一串数据:
cart = [] # 空购物车
while True:
item = input("输入要买的商品(输入 q 退出):")
if item == "q":
break # 用户说退出,跳出循环
cart.append(item) # 把商品加进列表
print(f"你的购物车:{cart}")
假设依次输入 牛奶、面包、q,输出:
输入要买的商品(输入 q 退出):牛奶
输入要买的商品(输入 q 退出):面包
输入要买的商品(输入 q 退出):q
你的购物车:['牛奶', '面包']
这里有几个坑提前说:
append一次只能加一个:fruits.append("a", "b")会报错。想一次加多个,用循环,或者extend。append是把整个东西当一个元素加进去:fruits.append(["a", "b"])会得到一个"列表套列表",元素本身是个列表。- 别忘了
break:while True没有退出条件会永远循环,程序卡死,按Ctrl + C强制停止。
删:从列表里拿走东西
删东西有三个方法,按"删谁"来选:
| 方法 | 作用 | 例子 |
|---|---|---|
remove(值) |
按值删,删第一个匹配的 | fruits.remove("香蕉") |
pop() |
按位置删,默认删最后一个,并返回删掉的值 | fruits.pop()、fruits.pop(0) |
clear() |
清空整个列表 | fruits.clear() |
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
fruits.remove("香蕉") # 按值删:删掉香蕉
print(fruits) # ['苹果', '橙子', '葡萄']
last = fruits.pop() # 删最后一个(葡萄),并且把葡萄接住
print(fruits) # ['苹果', '橙子']
print(last) # 葡萄
first = fruits.pop(0) # 按位置删:删第 0 个(苹果)
print(fruits) # ['橙子']
pop() 会"顺手"把删掉的值返回给你,这是它和 remove 最大的不同。对照着看更清楚:
cart = ["牛奶", "面包", "牛奶", "鸡蛋"]
cart.remove("牛奶") # 只删第一个"牛奶"
print(cart) # ['面包', '牛奶', '鸡蛋']
cart.pop(0) # 删第 0 个(现在第 0 个是"面包")
print(cart) # ['牛奶', '鸡蛋']
输出:
['面包', '牛奶', '鸡蛋']
['牛奶', '鸡蛋']
三个容易翻车的地方:
remove("不存在的东西")会报ValueError: list.remove(x): x not in list。删之前先in判断一下。remove只删第一个匹配的,列表里有两个同名商品,只删一个——上面例子就是证明。pop()不传参数删最后一个,pop(0)删第一个——pop 后面跟的是位置(下标),不是值。
改:替换列表里的东西
改最简单:直接给某个位置赋值。写法是 列表[下标] = 新值:
fruits = ["苹果", "香蕉", "橙子"]
fruits[0] = "大西瓜" # 把第 0 个(苹果)换成大西瓜
print(fruits) # ['大西瓜', '香蕉', '橙子']
配合 for 循环,还能批量改——比如给每个同学加 5 分:
scores = [80, 85, 90]
for i in range(len(scores)):
scores[i] = scores[i] + 5 # 每个人加 5 分
print(scores) # [85, 90, 95]
输出:
[85, 90, 95]
几个边界要记清:只能改已存在的位置,fruits[3] = "西瓜" 在只有 3 个元素的列表里会报 IndexError;想加新东西用 append / insert,赋值是"替换"不是"新增"。另外提醒一句:循环里改列表没问题,但循环里删列表元素容易出 bug(下标会错位),新手先别这么干,卡住了问 AI。
遍历:把每个元素过一遍
遍历就是用一个 for 循环,把列表里的元素从头到尾逐个拿出来处理。这是操作列表最核心的动作,没有之一:
fruits = ["苹果", "香蕉", "橙子"]
for f in fruits: # f 依次等于每个元素
print(f)
输出:
苹果
香蕉
橙子
遍历有两种常见写法,看你要不要"位置":
scores = [92, 85, 78]
# 写法一:直接拿元素(常用,够用)
for s in scores:
print(f"成绩:{s}")
# 写法二:拿下标再取元素(需要位置信息时用)
for i in range(len(scores)):
print(f"第 {i + 1} 个同学:{scores[i]}")
输出:
成绩:92
成绩:85
成绩:78
第 1 个同学:92
第 2 个同学:85
第 3 个同学:78
遍历最常见的搭档是"累加器"模式——在循环外面初始化一个变量,循环里更新它。最典型的例子是求和:
nums = [10, 20, 30, 40]
total = 0
for n in nums:
total = total + n # 把每个数累加进 total
print(total) # 100
输出:
100
统计个数、求和、找最大,全是这个套路:先 total = 0 之类地"起个头",再循环里更新。两个容易混的点:遍历的循环变量名(f、s、n)随便起,但要见名知意;for i in range(len(fruits)) 里的 i 是下标,fruits[i] 才是元素,别把两者搞混。
排序与统计:数字列表的常用操作
Python 给列表配了一批现成的小工具,写程序做数据分析时天天用:
| 方法 / 函数 | 作用 | 例子 | 结果 |
|---|---|---|---|
sort() |
原地排序(从小到大) | [3,1,2].sort() |
[1,2,3] |
reverse() |
原地倒序 | [1,2,3].reverse() |
[3,2,1] |
sorted(列表) |
排序后返回新列表(原列表不动) | sorted([3,1,2]) |
[1,2,3] |
max(列表) |
最大值 | max([3,1,2]) |
3 |
min(列表) |
最小值 | min([3,1,2]) |
1 |
sum(列表) |
求和 | sum([3,1,2]) |
6 |
nums = [3, 1, 2]
nums.sort() # 直接改 nums 自己
print(nums) # [1, 2, 3]
nums.reverse() # 倒过来
print(nums) # [3, 2, 1]
nums = [3, 1, 2] # 重新来一份
print(sorted(nums)) # [1, 2, 3](sorted 不改变原列表)
print(nums) # [3, 1, 2](原列表没动)
注意 sort() 和 sorted() 的区别:sort() 直接改原列表,sorted() 不动原列表、返回新的。记不住就统一用 sorted(),更安全。
综合用一下,成绩统计:
scores = [92, 85, 78, 95, 60]
print(f"最高分:{max(scores)}") # 最高分:95
print(f"最低分:{min(scores)}") # 最低分:60
print(f"总分:{sum(scores)}") # 总分:410
print(f"平均分:{sum(scores) / len(scores)}") # 平均分:82.0
scores.sort() # 排序
print(scores) # [60, 78, 85, 92, 95](从小到大)
输出:
最高分:95
最低分:60
总分:410
平均分:82.0
[60, 78, 85, 92, 95]
两个边界:sort() 对数字和字符串都能排,但一个列表里混着数字和字符串会报 TypeError: '<' not supported;sum() 只对数字列表有效,字符串列表用 sum 会报错。
列表推导式:一行生成列表(看懂即可)
列表推导式是一种"浓缩写法":用一行代码把"循环 + 生成列表"两件事一起做了。今天不要求会写,看懂、知道让 AI 用就行——面试和读代码时会碰到:
# 普通写法:循环生成 1~5 的平方
squares = []
for x in range(1, 6):
squares.append(x * x)
print(squares) # [1, 4, 9, 16, 25]
# 列表推导式:一行搞定(看懂即可)
squares2 = [x * x for x in range(1, 6)]
print(squares2) # [1, 4, 9, 16, 25]
输出:
[1, 4, 9, 16, 25]
[1, 4, 9, 16, 25]
推导式还能加条件——后面跟个 if 就行:
even = [x for x in range(1, 11) if x % 2 == 0]
print(even) # [2, 4, 6, 8, 10](1~10 里的偶数)
输出:
[2, 4, 6, 8, 10]
读法是:[表达式 for 变量 in 列表 if 条件],翻译成普通话就是"对列表里每个元素(满足条件的),把表达式的结果收进新列表"。记住两点:别为了炫技硬写推导式——逻辑复杂时普通 for 循环更好读,自己写程序优先用看得懂的写法;看到 AI 生成的推导式看不懂时,让 AI"用普通 for 循环改写",读代码就无压力了。
随堂练习
练习一:搭水果列表
建一个空列表,用 append 依次加入你喜欢的 3 种水果,打印出来;再用 insert 把一种水果插到最前面。
提示:空列表是 fruits = [];insert(0, "西瓜") 插到最前面。
练习二:改与删
把列表里第 2 个水果换成别的,删掉第 1 个,最后打印列表;再用 in 判断"你换的水果在不在列表里"。
提示:第 2 个的下标是 1;删第一个用 pop(0);判断用 if x in fruits:。
练习三(必做):购物车小程序
写一个小程序:提示用户输入商品名,输入 q 结束,用循环把商品加进列表,最后打印购物车,并打印"一共 N 件商品"。
提示:核心结构是 while True + input + if item == "q": break + cart.append(item)。下午实操必做,第 6 周项目会用到一模一样的逻辑。
进阶题(可选):购物车带统计
在练习三基础上,打印购物车前先排序(cart.sort()),再数一数有没有"牛奶"。
写不出来时,让 AI 搭把手
场景:购物车小程序写不出来,需要 AI 给参考代码
提示词:
我是 Python 初学者,今天学列表。请帮我写一个购物车小程序:
用 while 循环提示用户输入商品名,输入 q 退出,
把商品用 append 加进列表,最后打印购物车和商品数量。
代码加注释,用我能看懂的写法(不要用列表推导式)。
场景:想对列表做某个操作但不会,比如"列表里的数字求和"
提示词:
我有一个数字列表 scores = [92, 85, 78, 95, 60]。
请用最基础的方法(for 循环累加)算出总和和平均分,
不要用 sum() 函数,代码加注释。
常见报错速查
| 报错信息 | 什么意思 | 怎么办 |
|---|---|---|
IndexError: list index out of range |
下标越界,访问了不存在的元素 | 检查下标是否超过 len() - 1 |
AttributeError: 'list' object has no attribute 'push' |
调用了不存在的方法 | 列表添加用 append,push 是别的语言的习惯 |
ValueError: list.remove(x): x not in list |
remove 的东西不在列表里 |
删之前先用 in 判断,或改用 pop |
TypeError: '<' not supported between instances |
排序时列表里混了不同类型 | 保证列表里是同一类型(都是数字或都是字符串) |
收个尾
今天动手比较多,总结起来就一张图:增用 append(末尾)/ insert(指定位置);删用 pop(按位置)/ remove(按值);改直接 列表[下标] = 新值;查用下标 + in + for 遍历。遍历是核心动作,配合"累加器"模式能求和、能统计、能找最大;数字列表三件套 max / min / sum,排序用 sort()(改原列表)或 sorted()(返回新列表)。
明天学字典——列表的"带名字版本"。列表里的元素只能靠下标 [0]、[1] 找,字典里的数据能靠名字找:student["name"]。通讯录、成绩单这类"有名字的数据",字典才是主力。