5.3 字典及其应用
课程信息 - 课程名称:Python基础及应用 - 教学平台:Anaconda Jupyter Notebook

课前思考:在我们日常生活中,查字典是如何工作的?我们通过”关键词”(key)快速找到对应的”解释”(value)。Python中的字典正是借鉴了这一思想,让我们能够以极高的效率存储和查找数据。比如商品ID与价格、用户ID与信息、课程代码与成绩等,字典将是处理这些数据的得力工具!

5.3.1 字典概述
一、字典的概念
字典(Dictionary) 是Python中一种非常重要的映射类型(Mapping Type) 数据结构。与列表、元组等序列类型不同,字典中的数据不是按位置索引的,而是通过键(Key) 来访问值(Value) 的。
核心特征: - 键值对(Key-Value Pair) 存储:每个元素都是一个键值对,形如 key: value - 无序性(Python 3.7+ 中保持插入顺序,但这是实现细节,不应依赖) - 高效查找:通过键查找值的时间复杂度为 O(1),即常数时间
生活类比: - 📖 真实字典:通过”词语”找”释义” - 🏫 CK学校教务系统:通过”学号”找”学生信息” - 🗺️ 重庆地铁线路图:通过”站点名”找”换乘信息”

二、字典的定义
1. 使用花括号 {} 创建字典
# 基础语法:{键1: 值1, 键2: 值2, ..., 键n: 值n}# 示例1:创建一个空字典empty_dict = {}print(f"空字典:{empty_dict}, 类型:{type(empty_dict)}")# 示例2:CK学校部分专业信息字典ck_majors = {"数字经济": "经济管理学院", "工商管理": "经济管理学院", "计算机科学": "人工智能学院", "土木工程": "建筑学院", "环境设计": "艺术学院"}print(f"\nCK学校专业字典:{ck_majors}")# 示例3:重庆部分区县GDP数据(2023年模拟数据)cq_district_gdp = {"渝中区": 1560.5, "江北区": 1620.3, "渝北区": 2450.8, "九龙坡区": 1890.2, "沙坪坝区": 1120.6}print(f"\n重庆区县GDP字典:{cq_district_gdp}")
输出结果:
空字典:{}, 类型:CK学校专业字典:{'数字经济': '经济管理学院', '工商管理': '经济管理学院', '计算机科学': '人工智能学院', '土木工程': '建筑学院', '环境设计': '艺术学院'}重庆区县GDP字典:{'渝中区': 1560.5, '江北区': 1620.3, '渝北区': 2450.8, '九龙坡区': 1890.2, '沙坪坝区': 1120.6}
2. 使用 dict() 构造函数创建
# 方式1:通过关键字参数(键必须是合法的标识符)student_info =dict(name="张三", age=20, major="数字经济", school="CK")print(f"学生信息:{student_info}")# 方式2:通过可迭代对象(列表套元组/列表)courses =dict([("Python基础", 3.0),("经济学原理", 2.5),("数据分析", 3.5)])print(f"\n课程学分:{courses}")# 方式3:通过zip函数合并两个序列course_codes = ["CS101", "ECO201", "DAT301"]course_names = ["程序设计基础", "微观经济学", "大数据分析"]course_dict =dict(zip(course_codes, course_names))print(f"\n课程代码映射:{course_dict}")# 方式4:fromkeys() 创建具有默认值的字典# 场景:初始化CK学校5个学院的评分数组,初始分数都为0colleges = ["经济管理学院", "人工智能学院", "建筑学院", "艺术学院", "人文学院"]ratings =dict.fromkeys(colleges, 0)print(f"\n学院评分初始化:{ratings}")
输出结果:
学生信息:{'name': '张三', 'age': 20, 'major': '数字经济', 'school': 'CK'}课程学分:{'Python基础': 3.0, '经济学原理': 2.5, '数据分析': 3.5}课程代码映射:{'CS101': '程序设计基础', 'ECO201': '微观经济学', 'DAT301': '大数据分析'}学院评分初始化:{'经济管理学院': 0, '人工智能学院': 0, '建筑学院': 0, '艺术学院': 0, '人文学院': 0}
🔍 知识点串联回忆: - 这里的 zip() 函数我们在第4章循环中学过,它可以将多个可迭代对象”压缩”在一起 - dict.fromkeys() 中的默认值问题需要注意:如果默认值是可变对象(如列表),所有键将共享同一个对象!
# ⚠️ 陷阱演示:使用可变对象作为默认值wrong_init =dict.fromkeys(["A", "B", "C"], [])# 错误!三个键共享同一个列表wrong_init["A"].append(100)print(f"错误初始化结果:{wrong_init}")# 三个键的值都变成了[100]!# ✅ 正确做法:使用字典推导式(回顾第4章的循环知识)correct_init = {key: [] for key in ["A", "B", "C"]}correct_init["A"].append(100)print(f"正确初始化结果:{correct_init}")

三、键的不可变与唯一性
这是字典最核心的两个约束条件,理解它们对正确使用字典至关重要。
1. 键的不可变性(Immutability)
规则:字典的键必须是不可变类型(Immutable Type)。
哪些类型可以作为键? - ✅ 数值型:int, float(但需注意浮点精度问题) - ✅ 字符串:str(最常用的键类型) - ✅ 元组:tuple(但元组内元素也必须是不可变的) - ❌ 列表:list(可变,不能作为键) - ❌ 字典:dict(可变,不能作为键) - ❌ 集合:set(可变,不能作为键)
# ✅ 合法的字典键示例# 1. 字符串键(最常用)student_scores = {"张三": 85, "李四": 92, "王五": 78}print("字符串键:", student_scores)# 2. 整数键(适合序号、ID等)seat_assignment = {1: "张三", 2: "李四", 3: "王五"}print("整数键:", seat_assignment)# 3. 元组键(适合坐标、复合索引等)# 场景:CK学校教学楼座位预约系统,(楼层, 教室号, 座位号) 作为键reservation = {(1, 101, 15): "张三", (2, 205, 8): "李四", (3, 310, 22): "王五"}print("元组键:", reservation)# 4. 混合类型键(不推荐,但合法)mixed_keys = {"name": "CK学校", 2024: "建校年份", (29.56, 106.55): "重庆坐标"# 重庆的大致经纬度}print("混合键:", mixed_keys)
# ❌ 非法的字典键示例(会报错)# 尝试使用列表作为键try:invalid_dict = {["A", "B"]: "值"}# TypeError!exceptTypeErroras e:print(f"错误:{e}")# 尝试使用字典作为键try:invalid_dict2 = {{"a": 1}: "值"}# TypeError!exceptTypeErroras e:print(f"错误:{e}")# 尝试使用集合作为键try:invalid_dict3 = {{"A", "B"}: "值"}# TypeError!exceptTypeErroras e:print(f"错误:{e}")
为什么键必须不可变?
字典内部使用哈希表(Hash Table) 实现。键的哈希值在字典创建时计算,并用于确定值的存储位置。如果键可变,其哈希值会改变,导致无法找到对应的值!
# 哈希值演示print(f"'CK学校'的哈希值:{hash('CK学校')}")print(f"2024的哈希值:{hash(2024)}")print(f"(1, 2, 3)的哈希值:{hash((1, 2, 3))}")# 尝试获取列表的哈希值(会报错)try:print(hash([1, 2, 3]))exceptTypeErroras e:print(f"列表的哈希错误:{e}")
2. 键的唯一性(Uniqueness)
规则:字典中的键必须是唯一的。如果定义时重复,后面的值会覆盖前面的值。
# 键重复演示duplicate_keys = {"Python": 90, "Java": 85, "Python": 95# 重复的键,会覆盖前面的值}print(f"重复键结果:{duplicate_keys}")# 输出:{'Python': 95, 'Java': 85}# 实际应用场景:统计CK学校各学院的学生人数# 数据可能有重复录入,字典自动去重保留最后一条raw_data = [("经济管理学院", 1200),("人工智能学院", 800),("经济管理学院", 1250),# 更新后的数据("建筑学院", 600)]# 转换为字典(后面的值覆盖前面的)college_students =dict(raw_data)print(f"\n各学院学生人数:{college_students}")# 经济管理学院显示1250,而不是1200
🔍 知识点串联回忆: - 这与集合(Set)的”元素唯一性”类似(我们在5.4节会学到集合) - 回想第2章学的赋值语句:x = 5; x = 10,变量可以被覆盖,字典的值也是如此

5.3.2 字典处理
一、字典中数据的访问和处理
1. 通过键访问值(索引访问)
# 创建CK学校食堂评价字典ck_canteen = {"一食堂": 4.5, "二食堂": 4.2, "三食堂": 4.8, "美食街": 4.6, "教工餐厅": 4.9}# 基础访问print(f"三食堂评分:{ck_canteen['三食堂']}")# 访问不存在的键(会报错)try:print(ck_canteen["四食堂"])# KeyError!exceptKeyErroras e:print(f"访问错误:键 {e} 不存在")
2. 使用 get() 方法安全访问
# get() 方法:键不存在时返回None或默认值score1 = ck_canteen.get("三食堂")# 存在,返回4.8score2 = ck_canteen.get("四食堂")# 不存在,返回Nonescore3 = ck_canteen.get("四食堂", "暂无评分")# 不存在,返回默认值print(f"三食堂:{score1}")print(f"四食堂(无默认):{score2}")print(f"四食堂(有默认):{score3}")
对比总结: | 方式 | 键存在 | 键不存在 | 适用场景 | |——|——–|———-|———-| | dict[key] | 返回值 | 抛出KeyError | 确定键存在时 | | dict.get(key) | 返回值 | 返回None | 不确定键是否存在 | | dict.get(key, default) | 返回值 | 返回default | 需要默认值时 |
3. 添加和修改数据
# 创建重庆旅游景点门票价格字典(单位:元)cq_attractions = {"洪崖洞": 0, "解放碑": 0, "磁器口": 0, "长江索道": 20, "武隆天坑": 125}# 添加新键值对cq_attractions["大足石刻"] =140cq_attractions["三峡博物馆"] =0print(f"添加后:{cq_attractions}")# 修改已有键的值cq_attractions["长江索道"] =30# 涨价了print(f"修改后:{cq_attractions}")# 批量更新(使用update方法)new_attractions = {"白公馆": 0, "渣滓洞": 0, "南山一棵树": 30}cq_attractions.update(new_attractions)print(f"批量更新后:{cq_attractions}")# update也可以用来修改cq_attractions.update({"长江索道": 25, "武隆天坑": 135})print(f"批量修改后:{cq_attractions}")
4. 删除数据
# 创建CK学校图书馆借阅规则字典library_rules = {"本科生": 10, "研究生": 20, "教职工": 30, "临时卡": 2, "过期卡": 0}# 方法1:del 语句删除指定键del library_rules["过期卡"]print(f"del删除后:{library_rules}")# 方法2:pop() 删除并返回值grad_limit = library_rules.pop("研究生")print(f"pop返回值:{grad_limit}")print(f"pop删除后:{library_rules}")# 方法3:popitem() 删除并返回最后插入的键值对(LIFO)# Python 3.7+ 保持插入顺序,所以删除的是最后添加的last_item = library_rules.popitem()print(f"popitem返回值:{last_item}")print(f"popitem删除后:{library_rules}")# 方法4:clear() 清空字典temp_dict = {"A": 1, "B": 2}temp_dict.clear()print(f"清空后:{temp_dict}")

二、字典的运算符和表达式
1. 成员运算符:in 和 not in
# 创建CK学校专业设置字典ck_programs = {"数字经济": "本科", "大数据管理": "本科", "人工智能": "本科", "土木工程": "本科", "建筑学": "本科", "视觉传达": "专科"}# 判断键是否存在(注意:只能判断键,不能判断值!)print(f"'数字经济'是否在专业中:{'数字经济'in ck_programs}")print(f"'金融学'是否在专业中:{'金融学'in ck_programs}")print(f"'专科'是否在专业中:{'专科'in ck_programs}")# False!这是值不是键# 结合第3章分支结构使用major =input("请输入专业名称:")if major in ck_programs:level = ck_programs[major]print(f"{major}是{level}专业")else:print(f"抱歉,CK学校没有开设{major}专业")
🔍 知识点串联回忆: - in 运算符在第4章循环中用于遍历:for item in iterable: - 在字典中,in 判断的是键,不是值!这与列表、元组不同(它们判断的是元素)
2. 比较运算符
# 字典的比较(Python 3中移除了<, >等比较,只保留==和!=)dict1 = {"A": 1, "B": 2}dict2 = {"B": 2, "A": 1}# 顺序不同dict3 = {"A": 1, "B": 3}print(f"dict1 == dict2(顺序不同):{dict1 == dict2}")# True,字典无序print(f"dict1 == dict3(值不同):{dict1 == dict3}")# Falseprint(f"dict1 != dict3:{dict1 != dict3}")# True
3. 身份运算符:is 和 is not
# 回顾第3章学的is运算符dict_a = {"重庆": "山城", "CK": "学校"}dict_b = {"重庆": "山城", "CK": "学校"}dict_c = dict_a# 引用赋值print(f"dict_a == dict_b:{dict_a == dict_b}")# True,值相等print(f"dict_a is dict_b:{dict_a is dict_b}")# False,不同对象print(f"dict_a is dict_c:{dict_a is dict_c}")# True,同一对象# 复制字典(浅拷贝)dict_d = dict_a.copy()print(f"dict_a is dict_d:{dict_a is dict_d}")# Falseprint(f"dict_a == dict_d:{dict_a == dict_d}")# True

三、字典处理函数
Python提供了多个内置函数用于处理字典。
# 创建测试数据:CK学校2024级数字经济班学生成绩scores = {"张重庆": 92, "李嘉陵": 85, "王长江": 78, "赵山城": 95, "刘火锅": 88}# 1. len() - 返回键值对数量(第2章学过的函数)print(f"学生人数:{len(scores)}")# 2. sorted() - 对键进行排序(第2章学过的函数)print(f"按姓名排序:{sorted(scores)}")print(f"按姓名降序:{sorted(scores, reverse=True)}")# 3. max() 和 min() - 对键进行操作print(f"姓名字母最大:{max(scores)}")print(f"姓名字母最小:{min(scores)}")# 4. 结合values()获取最大最小值print(f"最高分:{max(scores.values())}")print(f"最低分:{min(scores.values())}")# 5. sum() - 对数值求和print(f"总分:{sum(scores.values())}")print(f"平均分:{sum(scores.values()) /len(scores):.2f}")# 6. all() 和 any() - 判断键的真值(回顾第3章逻辑运算)# 空字符串为False,非空为Truetest_dict = {"A": 1, "": 2, "B": 3}print(f"all(keys):{all(test_dict)}")# False,因为有空字符串键print(f"any(keys):{any(test_dict)}")# True

四、字典处理方法
字典对象提供了丰富的方法,以下是核心方法详解:
1. 视图对象方法:keys(), values(), items()
这三个方法返回视图对象(View Object),是动态的,会随字典变化而更新。
# 创建CK学校校区信息字典ck_campuses = {"重庆校区": 1200,# 亩"四川校区": 800, "贵州校区": 600}# keys() - 返回所有键的视图keys_view = ck_campuses.keys()print(f"所有校区:{keys_view}")print(f"类型:{type(keys_view)}")# values() - 返回所有值的视图values_view = ck_campuses.values()print(f"\n所有面积:{values_view}")# items() - 返回所有键值对的视图(元组形式)items_view = ck_campuses.items()print(f"\n所有项:{items_view}")# 视图是动态的!ck_campuses["沙坪坝校区"] =400print(f"\n添加新校区后,keys更新:{keys_view}")print(f"添加新校区后,items更新:{items_view}")
2. 遍历字典(结合第4章循环知识)
# 创建重庆各区县人口数据(万人,2023年模拟数据)cq_population = {"渝中区": 58.7, "大渡口区": 42.5, "江北区": 92.8, "沙坪坝区": 147.7, "九龙坡区": 152.9, "南岸区": 120.2, "北碚区": 83.4, "渝北区": 224.5, "巴南区": 118.0}# 方式1:遍历键(默认)print("=== 遍历键(区县名)===")for district in cq_population:print(district, end=" ")print()# 方式2:显式使用keys()print("\n=== 显式遍历键 ===")for district in cq_population.keys():print(f"{district}区", end=" ")print()# 方式3:遍历值print("\n=== 遍历值(人口)===")total_pop =0for pop in cq_population.values():total_pop += pop# 累加,回顾第2章赋值运算print(f"总人口:{total_pop:.1f}万人")# 方式4:遍历键值对(最常用)print("\n=== 遍历键值对 ===")for district, pop in cq_population.items():print(f"{district}: {pop}万人")
3. 其他常用方法
# setdefault() - 键不存在时设置默认值,存在则返回原值# 场景:统计CK学校学生活动参与次数participation = {"张三": 3, "李四": 5}# 王五第一次参加,不存在,设置为1wang5_count = participation.setdefault("王五", 1)print(f"王五参与次数:{wang5_count}")# 张三已存在,返回原值3,不修改zhang3_count = participation.setdefault("张三", 10)print(f"张三参与次数:{zhang3_count}(未被覆盖)")print(f"当前字典:{participation}")# fromkeys() - 已讲过,类方法,创建新字典# copy() - 浅拷贝original = {"A": [1, 2], "B": [3, 4]}copied = original.copy()copied["A"].append(999)# 修改拷贝中的列表print(f"\n原始:{original}")# 也被修改了!因为是浅拷贝print(f"拷贝:{copied}")# 深拷贝需要copy模块(本章不涉及,后续章节会讲)

🤖 AI辅助学习环节:用AI深化字典学习
教学目标:通过与AI对话,完成有趣的编程练习,巩固字典知识,同时激发学习兴趣。
练习一:重庆美食地图可视化
目标:创建一个重庆特色美食的交互式查询系统,包含价格、辣度、推荐店铺等信息。
给AI的提示词(Prompt):
请帮我用Python字典编写一个"重庆美食地图"程序,要求:1. 使用嵌套字典存储至少8种重庆特色美食(如火锅、小面、酸辣粉等),每种食物包含:- 价格区间(字符串,如"15-30元")- 辣度等级(1-5星)- 推荐店铺(列表,包含3家店名)- 特色标签(列表,如["麻辣", "鲜香"])2. 实现以下功能函数:- 显示所有美食(格式化表格输出)- 按辣度筛选(输入辣度等级,显示所有匹配美食)- 随机推荐(使用random模块随机推荐一种美食)- 搜索功能(按美食名称关键词搜索)3. 使用while循环实现交互式菜单,用户可以反复查询直到选择退出4. 添加一些重庆方言的趣味输出(如"巴适得板"、"好安逸"等)请提供完整可运行的代码,并解释其中字典的使用技巧。
学习要点: - 嵌套字典的设计 - 字典与列表的组合使用 - 循环和分支的结合 - 字符串格式化输出

练习二:CK学校宿舍分配系统
目标:模拟学校宿舍分配管理,练习字典的增删改查。
给AI的提示词(Prompt):
请帮我用Python编写一个"CK学校宿舍管理系统",使用字典作为主要数据结构:1. 数据结构要求:- 宿舍楼为键,值为该楼层的房间字典- 每个房间包含:房间号、已住人数、最大容量、学生名单(列表)- 学生信息用字典存储:姓名、学号、专业、入住日期2. 实现功能:- 初始化3栋宿舍楼(梅园、兰园、竹园),每栋楼3层,每层5个房间,4人间- 学生入住(检查容量,更新字典)- 学生退宿(从房间移除,更新人数)- 查询空床位(统计所有可入住房间)- 查询学生住宿信息(输入学号,返回所在楼栋、房间、室友)- 换宿功能(从原房间移除,加入新房间)3. 要求使用字典方法:get(), pop(), update(), keys(), values(), items()4. 添加数据验证:防止超员、防止查无此人等请提供代码并解释字典的嵌套结构和操作方法。
学习要点: - 多层嵌套字典的设计与访问 - 字典作为数据库的模拟 - 复杂数据的增删改查 - 异常处理(结合第3章try-except)

练习三:生成个性化课表(结合第4章循环)
目标:生成美观的ASCII课表,练习字典与循环的结合。
给AI的提示词(Prompt):
请帮我用Python生成一个"CK学校个性化课表生成器":1. 使用字典存储课程信息:- 键:星期几(1-5)+ 节次(1-4)组成的元组,如(1, 2)表示周一第2节- 值:课程信息字典,包含课程名、教室、教师2. 实现功能:- 添加课程(输入星期、节次、课程信息)- 删除课程- 显示课表(使用ASCII字符画成表格形式,如+----+----+)- 检查冲突(同一时间段不能有两门课)- 统计每周课时数、空闲时间段3. 美化输出:- 使用不同符号表示不同类型的课程(专业课★、选修课○、实验课◆)- 添加颜色(使用ANSI转义码,如\033[31m红色\033[0m)4. 保存功能:将课表字典保存到文本文件(预习第7章文件操作)请提供代码,并重点解释如何使用字典的键来唯一标识时间和课程的关系。
学习要点: - 元组作为字典键(不可变性) - 字典的遍历与格式化输出 - 字典用于二维数据(时间+课程)的存储 - 简单的文件操作预习

练习四:重庆方言词典(趣味项目)
目标:创建一个可交互的重庆方言学习词典。
给AI的提示词(Prompt):
请帮我创建一个"重庆方言学习词典"Python程序:1. 使用字典存储重庆方言词汇:- 键:方言词汇(如"巴适"、"要得"、"雄起")- 值:包含释义的嵌套字典- meaning: 普通话解释- usage: 使用场景- example: 例句- difficulty: 难度等级(1-3)- related: 相关词汇列表2. 实现功能:- 查询功能(输入方言,返回详细解释)- 随机学习(随机返回一个方言及其用法)- 按难度浏览(只显示指定难度的词汇)- 添加新词汇(用户可扩充词典)- 测验模式(显示释义,让用户输入对应方言)- 显示统计信息(总词汇数、各难度数量)3. 趣味功能:- 每日一句(随机显示一个方言例句)- 模拟对话(使用几个方言词汇生成一段对话)4. 要求:- 使用字典推导式创建子集(如只选难度1的词汇)- 使用sorted()对词汇排序- 使用json模块保存和加载词典(预习第7章)请提供完整代码,并解释如何用字典组织复杂的结构化数据。
学习要点: - 字典存储复杂结构化数据 - 字典推导式(高级用法) - 字典的持久化存储(JSON) - 交互式程序设计

练习五:爱心代码生成器(结合第2章字符串)
目标:用字典存储不同风格的爱心图案,练习字符串操作。
给AI的提示词(Prompt):
请帮我创建一个"Python爱心代码生成器",使用字典管理不同风格的爱心图案:1. 使用字典存储至少5种不同风格的爱心图案:- simple: 使用*符号组成的简单爱心- math: 使用数学公式(如心形线方程)生成的坐标爱心- emoji: 使用emoji字符组成的爱心- ascii: 使用ASCII艺术的大爱心- code: 使用Python代码本身形状组成的爱心(meta)2. 每种风格包含:- pattern: 多行字符串(使用三引号)- description: 风格描述- difficulty: 复制难度(1-5)- tags: 标签列表3. 实现功能:- 展示所有风格(带编号)- 按编号选择并打印爱心- 添加自定义爱心(用户输入多行文本)- 随机爱心(随机选择一种展示)- 爱心动画(使用换行符模拟跳动效果,结合time.sleep)4. 进阶功能:- 在爱心中嵌入指定文字(如"重庆"、"Python")- 彩色爱心(使用ANSI颜色代码)请提供代码,并解释如何使用字典管理多行文本和复杂字符串。
学习要点: - 字典存储多行字符串 - 字符串的复杂操作(替换、格式化) - 简单的动画效果(循环+延时) - 用户输入处理

如何与AI对话学习(操作指南)
步骤1:选择上面的一个提示词,复制到AI对话工具
步骤2:观察AI生成的代码,重点关注: - 字典是如何定义和初始化的? - 使用了哪些字典方法? - 如何处理嵌套结构? - 异常处理是如何实现的?
步骤3:向AI提出修改要求,例如: - “请把字典的键从字符串改成元组” - “请添加一个按值排序的功能” - “请用字典推导式重构这部分代码” - “请解释为什么这里要用get()而不是[]”
步骤4:自己动手修改代码,然后让AI检查: - “我修改了这部分,你看对吗?” - “我尝试用pop()代替del,这样有什么好处?”
步骤5:拓展提问: - “如果数据量很大,字典和列表哪个查询更快?” - “字典的键可以是对象吗?” - “如何实现字典的深拷贝?”
