第3章 3.1 索引数组与关联数组
学习目标:学完本文,你能用 Python 的「列表」和「字典」管理一堆数据,再也不用手忙脚乱地数第几个元素了。
🎯 开场 3 分钟:为什么要学这个?
你有没有遇到过这种情况——
双十一老婆让你帮她记购物车里的宝贝:「那个粉色的、对就是那个、贵的那个……」
你内心 OS:「到底是哪个???」
这就是没有给数据贴标签的痛苦。想象一下,如果购物车里的每件商品都有一张「小票」,写着「商品名叫啥、价格多少、还剩几件」,那该多清楚!
编程里,索引数组(列表)就是那张「按顺序编号的小票」,关联数组(字典)就是那张「写满标签的详细小票」。
今天这套组合拳学会了,以后处理 Excel、JSON 接口返回、爬虫数据,全都不在话下。
🧱 基础 25 分钟:核心概念
3.1.1 索引数组(列表)= 食堂打饭的餐盘
生活类比:食堂打饭的时候,每个菜放在一个格子里,从左到右排成一排。第一格是米饭,第二格是红烧肉,第三格是青菜……你知道「第二格\n\n
\n\n
\n\n」就是红烧肉,不需要记它叫啥。
Python 里的列表就是这个原理——一堆元素排排坐,每个位置有个编号(从 0 开始)。
为什么要用:当你有一堆「同类东西」需要按顺序放着、挨个处理的时候。比如:10 个用户的名字、一个月每天的温度、一购物车的商品。
怎么用:
# 创建一个购物清单(索引数组)
fruits = ["苹果", "香蕉", "橙子", "草莓"]
# 按位置取第三个水果(注意!位置是从 0 开始数的)
print(fruits[2]) # 输出:橙子
这行代码在干嘛:取出
fruits里第 3 个位置的东西。类比食堂打饭——走到第 3 格拿橙子。
3.1.2 关联数组(字典)= 带名牌的快递柜
生活类比:小区快递柜大家都见过吧?每个格子里放的是「1-2-3 号张阿姨的快递」「2-1-5 号李叔叔的快递」——每个格子有个「编号 + 收件人」的双重标签。
Python 里的字典就是这个原理——每个元素有一个「名字」(叫 key),对应一个「值」(叫 value)。
为什么要用:当你需要「根据名字找东西」的时候。比如:根据用户名查用户信息、根据商品 ID 查价格、根据城市名查天气。
怎么用:
# 创建一个用户信息(关联数组)
user = {
"name": "张三",
"age": 28,
"city": "北京"
}
# 根据名字取年龄
print(user["age"]) # 输出:28
这行代码在干嘛:从
user字典里找到「age」这个标签对应的值。类比快递柜——找到「李叔叔」那个格子,看里面是啥。
3.1.3 混合使用:购物车里的战斗机
真实场景往往是列表里套字典,就像一个购物车里放着好几件商品,每件商品有自己的详细信息:
# 购物车:3 件商品,每件商品是一个字典
cart = [
{"name": "iPhone 15", "price": 6999, "count": 1},
{"name": "AirPods Pro", "price": 1899, "count": 2},
{"name": "MagSafe", "price": 299, "count": 1}
]
# 算算总价
total = 0
for item in cart:
total += item["price"] * item["count"]
print(f"总价:{total} 元") # 输出:总价:10796 元
这段代码在干嘛:遍历购物车每件商品,把价格乘数量加起来。类比——收银员扫每件商品的条码,结账总额。
3.1.4 常用操作 5 分钟入门
下面这些操作,抄过去就能跑,遇到类似场景直接复制改名字就行:
# 1. 创建空列表 / 空字典
empty_list = []
empty_dict = {}
# 2. 添加元素
fruits = ["苹果", "香蕉"]
fruits.append("橙子") # 列表末尾加一个
print(fruits) # 输出:['苹果', '香蕉', '橙子']
# 3. 修改元素
fruits[0] = "大苹果" # 把第 1 个改成大苹果
print(fruits) # 输出:['大苹果', '香蕉', '橙子']
# 4. 删除元素
del fruits[1] # 删掉第 2 个
print(fruits) # 输出:['大苹果', '橙子']
# 5. 字典增改
user = {"name": "张三"}
user["age"] = 28 # 新增一个键值对
user["name"] = "李四" # 修改已有的键
print(user) # 输出:{'name': '李四', 'age': 28}
# 6. 获取长度
print(len(fruits)) # 输出:2(几个元素)
print(len(user)) # 输出:2(几个键值对)
# 7. 检查键是否存在
if "age" in user:
print(f"年龄是 {user['age']}") # 输出:年龄是 28
记住口诀:列表用位置,字典用名字,混合用循环。
3.1.5 列表推导式:一行代码搞定「筛选 + 转换」
这是 Python 的独门秘籍,其他语言要写好几行,Python 一行搞定。
生活类比:你去自助餐厅,想把所有甜品挑出来——列表推导式就是那个帮你快速挑菜的小托盘。
# 场景:把购物车里价格超过 1000 块的商品挑出来
cart = [
{"name": "iPhone 15", "price": 6999},
{"name": "数据线", "price": 29},
{"name": "AirPods Pro", "price": 1899}
]
# 传统写法(3 行)
expensive = []
for item in cart:
if item["price"] > 1000:
expensive.append(item)
# 列表推导式(1 行搞定)
expensive = [item for item in cart if item["price"] > 1000]
print(expensive)
# 输出:[{'name': 'iPhone 15', 'price': 6999}, {'name': 'AirPods Pro', 'price': 1899}]
读法:从 cart 里,把每个 item(如果你喜欢可以改名),但只保留 price > 1000 的。翻译成人话——「把所有贵的挑出来」。
🔥 实战 35 分钟:3 个递进的小项目
项目 1(5 分钟):班级成绩统计器
需求:输入 5 个人的成绩,统计平均分和最高分。
# -*- coding: utf-8 -*-
# 班级成绩统计器
scores = [85, 92, 78, 96, 88]
average = sum(scores) / len(scores)
max_score = max(scores)
min_score = min(scores)
print(f"班级平均分:{average:.1f}")
print(f"最高分:{max_score},最低分:{min_score}")
# 顺便找出最高分的是谁(这里用位置模拟姓名)
top_index = scores.index(max_score)
names = ["小明", "小红", "小刚", "小芳", "小李"]
print(f"最高分选手:{names[top_index]}")
预期输出:
班级平均分:87.8
最高分:96,最低分:78
最高分选手:小芳
一句话解释:用 sum/len/max 三个函数搞定统计,index() 找到最高分的位置,再用位置找对应姓名。
项目 2(15 分钟):CSV 文件读取 + 数据清洗
需求:读取一份「用户消费记录.csv」,找出消费总额前 3 的用户,打印排行榜。
先模拟一个 CSV 文件内容(实际运行时存成 data.csv):
用户名,城市,消费金额
张三,北京,3500
李四,上海,8200
王五,广州,1500
赵六,深圳,6700
小明,北京,4200
小红,上海,9800
完整可运行代码:
# -*- coding: utf-8 -*-
# 用户消费排行榜
import csv
# 模拟 CSV 数据(实际用 open('data.csv', encoding='utf-8') 读取)
csv_data = """用户名,城市,消费金额
张三,北京,3500
李四,上海,8200
王五,广州,1500
赵六,深圳,6700
小明,北京,4200
小红,上海,9800"""
# 解析 CSV
lines = csv_data.strip().split("\n")
reader = csv.DictReader(lines)
# 转换成字典列表
users = []
for row in reader:
users.append({
"name": row["用户名"],
"city": row["城市"],
"spending": int(row["消费金额"])
})
# 按消费金额排序(降序)
sorted_users = sorted(users, key=lambda x: x["spending"], reverse=True)
# 打印前 3 名
print("🏆 消费排行榜 TOP 3")
print("-" * 25)
for i, user in enumerate(sorted_users[:3], 1):
medal = ["🥇", "🥈", "🥉"][i-1]
print(f"{medal} 第{i}名:{user['name']}({user['city']})- 消费 {user['spending']} 元")
预期输出:
🏆 消费排行榜 TOP 3
-------------------------
🥇 第1名:小红(上海)- 消费 9800 元
🥈 第2名:李四(上海)- 消费 8200 元
🥉 第3名:赵六(深圳)- 消费 6700 元
一句话解释:csv.DictReader 自动把每行转成字典,sorted 加 lambda 按消费金额倒序排列。
项目 3(15 分钟):待办事项管理器(命令行版)
需求:做一个命令行待办清单,能增、查、显、删。用字典存每个待办事项的详情。
# -*- coding: utf-8 -*-
# 命令行待办事项管理器
todos = []
def add_todo():
task = input("请输入新任务:")
priority = input("优先级(高/中/低):")
todos.append({
"task": task,
"priority": priority,
"done": False
})
print(f"✅ 已添加:「{task}」")
def list_todos():
if not todos:
print("📭 没有任何待办事项")
return
print("\n📋 待办清单")
print("-" * 40)
for i, item in enumerate(todos, 1):
status = "✅" if item["done"] else "⬜"
tag = {"高": "🔴", "中": "🟡", "低": "🟢"}.get(item["priority"], "⚪")
done_mark = "(已完成)" if item["done"] else ""
print(f"{i}. {status} {tag}{item['task']} {done_mark}")
def done_todo():
list_todos()
if not todos:
return
idx = int(input("输入要完成的任务编号:")) - 1
if 0 <= idx < len(todos):
todos[idx]["done"] = True
print(f"🎉 「{todos[idx]['task']}」已完成!")
else:
print("❌ 编号无效")
def delete_todo():
list_todos()
if not todos:
return
idx = int(input("输入要删除的任务编号:")) - 1
if 0 <= idx < len(todos):
removed = todos.pop(idx)
print(f"🗑️ 已删除:「{removed['task']}」")
else:
print("❌ 编号无效")
# 主循环
while True:
print("\n📌 待办事项管理器")
print("1. 添加任务 2. 查看全部 3. 标记完成 4. 删除任务 5. 退出")
choice = input("请选择:")
if choice == "1":
add_todo()
elif choice == "2":
list_todos()
elif choice == "3":
done_todo()
elif choice == "4":
delete_todo()
elif choice == "5":
print("下次见!👋")
break
else:
print("⚠️ 无效选择,请重新输入")
预期输出(示例交互):
📌 待办事项管理器
1. 添加任务 2. 查看全部 3. 标记完成 4. 删除任务 5. 退出
请选择:1
请输入新任务:写周报
优先级(高/中/低):高
✅ 已添加:「写周报」
📌 待办事项管理器
1. 添加任务 2. 查看全部 3. 标记完成 4. 删除任务 5. 退出
请选择:2
📋 待办清单
----------------------------------------
1. ⬜ 🔴写周报
一句话解释:用列表存所有待办,每个待办是个字典包含任务名、优先级、是否完成,增删改查全靠列表的 append/pop 和字典的键值访问。
💪 进阶 20 分钟:常见坑 + 性能小贴士
坑 1:列表切片越界不会报错?
# ❌ 错误示范
fruits = ["苹果", "香蕉"]
print(fruits[5]) # 越界了,Python 会直接报错 IndexError
# ✅ 正确示范
fruits = ["苹果", "香蕉"]
if len(fruits) > 5:
print(fruits[5])
else:
print("只有 2 个水果,没有第 6 个")
说白了:列表是个老实人,你问它要第 6 个它没有,它会直接喊「没有!」报错。取之前先数数有几个。
坑 2:字典访问键不存在会炸?
# ❌ 错误示范
user = {"name": "张三"}
print(user["age"]) # 报错 KeyError: 'age'
# ✅ 正确示范 1:用 get 方法(推荐)
print(user.get("age", "未知")) # 输出:未知(安全取,不报错)
# ✅ 正确示范 2:先检查有没有
if "age" in user:
print(user["age"])
说白了:
get像是带保险的访问——你要的东西没有,它返回一个默认值而不是直接崩溃。
坑 3:列表里套字典,修改时搞错对象?
# ❌ 错误示范:以为修改的是复制,其实改的是原数据
users = [{"name": "张三"}, {"name": "李四"}]
target = users[0]
target["name"] = "王五"
print(users[0]["name"]) # 输出:王五(原来的也被改了!)
# ✅ 正确示范:用 deepcopy 如果真的需要独立副本
from copy import deepcopy
users = [{"name": "张三"}, {"name": "李四"}]
target = deepcopy(users[0])
target["name"] = "王五"
print(users[0]["name"]) # 输出:张三(原来的没变)
说白了:列表里存的是「房卡」不是「房子」,你拿到的只是引用。要真正复制一份房子,得用
deepcopy。
坑 4:循环里修改列表导致索引错位?
# ❌ 错误示范:边遍历边删,会漏删或报错
nums = [1, 2, 3, 4, 5]
for i, n in enumerate(nums):
if n % 2 == 0:
del nums[i]
print(nums) # 结果可能不是 [1, 3, 5]!
# ✅ 正确示范:过滤出新列表
nums = [1, 2, 3, 4, 5]
nums = [n for n in nums if n % 2 != 0] # 列表推导式过滤
print(nums) # 输出:[1, 3, 5]
说白了:不要在数数的过程中删人,数着数着就乱了。
坑 5:字典的键大小写敏感?
# ❌ 错误示范:以为 Key 和 key 是同一个
config = {"Key": "value1"}
print(config["key"]) # 报错 KeyError
# ✅ 正确示范:统一大小写
config = {"key": "value1"}
print(config["key"]) # 输出:value1
性能小贴士:列表推导式比普通循环快
import time
# 性能测试
n = 1000000
# 方式 1:普通循环
start = time.time()
result1 = []
for i in range(n):
result1.append(i * 2)
print(f"普通循环:{time.time() - start:.3f}秒")
# 方式 2:列表推导式
start = time.time()
result2 = [i * 2 for i in range(n)]
print(f"列表推导式:{time.time() - start:.3f}秒")
列表推导式通常快 30%-50%,因为 Python 底层对它有优化。
调试技巧:print 大法已经够用了
# 场景:不知道循环里发生了什么
cart = [
{"name": "iPhone", "price": 6999},
{"name": "数据线", "price": 29}
]
for item in cart:
print(f"DEBUG: 正在处理 {item['name']}, 价格={item['price']}")
# 看到输出没问题后,删掉这行或注释掉
说白了:别小看
pdb或logging。
✏️ 练习题
练习 1(2 分钟):改改数据
- 输入:
[10, 20, 30, 40, 50] - 预期输出:
第三个元素是 30 - 提示:
list[index]的 index 从 0 开始
练习 2(2 分钟):加个判断
- 输入:列表
[85, 92, 78] - 预期输出:如果最高分大于 90,输出「优秀」,否则输出「还需努力」
- 提示:
max()求最大值,配合if判断
练习 3(3 分钟):处理新数据
- 输入:字典
{"北京": 22, "上海": 25, "广州": 28, "深圳": 30} - 预期输出:打印每个城市和温度,格式:
城市:温度℃ - 提示:用
for city, temp in dict.items()遍历
练习 4(5 分钟):串联两个项目
- 输入:用户列表
[{"name": "A", "score": 85}, {"name": "B", "score": 92}] - 预期输出:找出最高分的人,打印
最高分是:B,92分 - 提示:参考项目 1 的
max+ 项目 2 的字典取值
练习 5(5 分钟):这个报错啥意思?
# 代码
d = {"name": "张三"}
print(d["age"])
# 报错信息
# KeyError: 'age'
- 问题:为什么会报错?怎么修?
- 提示:字典里没有
age这个键
作业:做一个「个人记账本」
需求:做一个命令行记账工具,能记录收入和支出,查询指定月份的统计。
功能点:
1. 添加账目(收入/支出、金额、备注、月份)
2. 查看所有账目
3. 按月份统计(该月总收入、总支出、结余)
4. 删除指定账目
加分项:
1. 数据持久化(存到文件里,重启不丢)
2. 支持按类型筛选(只看支出或只看收入)
验收标准:
- 能跑起来
- 每个功能有明确输出
- 代码有适当注释
提交方式:评论区贴代码或 GitHub 链接
📚 总结 + 资源
本文学了 3 件事:
1. 列表(索引数组)= 按位置编号的容器,用 [] 操作
2. 字典(关联数组)= 带名字标签的容器,用 [] 或 .get() 操作
3. 列表里套字典 = 处理真实业务数据的黄金组合
延伸学习资源:
- 官方文档:Python 列表 | Python 字典
- 书籍:《Python 编程:从入门到实践》第 5 章「字典」
互动钩子:你在实际工作或生活中,用列表和字典解决过什么问题?评论区聊聊,老粉优先回复!👇
📌 下章预告:学会了列表和字典的基本操作,下一章我们要学习 20 个高阶数组函数,让数据处理快到飞起~

评论(0)