
引言:为什么需要字典和集合?
在前面的课程中,我们学习了列表和元组,它们可以存储一组数据。但如果我们需要通过一个标识来快速查找数据呢?
比如:
- 通过学号查找学生的成绩
- 通过用户名查找用户信息
- 通过城市名查找天气信息
这时候就需要用到字典。字典通过"键值对"的方式存储数据,可以快速查找。
而集合则用于存储不重复的元素,常用于去重和集合运算。
一、字典的键值对
1. 什么是字典
字典是Python中的一种数据结构,用于存储"键值对"(key-value pairs)。每个键对应一个值,通过键可以快速查找对应的值。
python
# 创建字典
student = {
"name": "小明",
"age": 20,
"score": 95
}
print(student) # 输出:{'name': '小明', 'age': 20, 'score': 95}
# 空字典
empty_dict = {}
print(empty_dict) # 输出:{}
# 使用dict()函数创建
student = dict(name="小明", age=20, score=95)
print(student) # 输出:{'name': '小明', 'age': 20, 'score': 95}
💡 提示:字典的键必须是不可变类型(如字符串、数字、元组),值可以是任意类型。
2. 访问字典元素
python
student = {
"name": "小明",
"age": 20,
"score": 95
}
# 使用键访问值
print(student["name"]) # 输出:小明
print(student["age"]) # 输出:20
print(student["score"]) # 输出:95
# 使用get()方法(推荐)
print(student.get("name")) # 输出:小明
print(student.get("gender")) # 输出:None(键不存在时返回None)
print(student.get("gender", "未知")) # 输出:未知(可以指定默认值)
💡 提示 :使用
[]访问不存在的键会报错,使用get()方法更安全。
python
# ❌ 使用[]访问不存在的键
# print(student["gender"]) # KeyError: 'gender'
# ✅ 使用get()方法
print(student.get("gender", "未知")) # 输出:未知
3. 字典的特点
python
student = {
"name": "小明",
"age": 20,
"score": 95
}
# 1. 键必须是唯一的
student = {
"name": "小明",
"name": "小红" # 后面的值会覆盖前面的
}
print(student) # 输出:{'name': '小红'}
# 2. 键必须是不可变类型
# ✅ 可以使用字符串、数字、元组作为键
valid_dict = {
"name": "小明",
1: "数字键",
(1, 2): "元组键"
}
# ❌ 不能使用列表、字典作为键
# invalid_dict = {
# [1, 2]: "列表键" # TypeError: unhashable type: 'list'
# }
# 3. 字典是无序的(Python 3.7+ 保持插入顺序)
print(student) # 输出顺序与插入顺序一致
二、字典的增删改查
1. 增加元素
python
student = {
"name": "小明",
"age": 20
}
# 直接赋值添加新键值对
student["score"] = 95
print(student) # 输出:{'name': '小明', 'age': 20, 'score': 95}
# 使用update()方法添加多个键值对
student.update({"gender": "男", "city": "北京"})
print(student) # 输出:{'name': '小明', 'age': 20, 'score': 95, 'gender': '男', 'city': '北京'}
# update()也可以修改已存在的键
student.update({"age": 21})
print(student) # 输出:{'name': '小明', 'age': 21, 'score': 95, 'gender': '男', 'city': '北京'}
2. 删除元素
python
student = {
"name": "小明",
"age": 20,
"score": 95,
"gender": "男"
}
# 使用del删除指定键值对
del student["gender"]
print(student) # 输出:{'name': '小明', 'age': 20, 'score': 95}
# 使用pop()删除并返回值
age = student.pop("age")
print(age) # 输出:20
print(student) # 输出:{'name': '小明', 'score': 95}
# 使用popitem()删除最后一个键值对(Python 3.7+)
last_item = student.popitem()
print(last_item) # 输出:('score', 95)
print(student) # 输出:{'name': '小明'}
# 使用clear()清空字典
student.clear()
print(student) # 输出:{}
💡 提示:
pop()可以指定默认值,键不存在时返回默认值popitem()在空字典上调用会报错
python
student = {"name": "小明"}
# 使用pop()指定默认值
gender = student.pop("gender", "未知")
print(gender) # 输出:未知
3. 修改元素
python
student = {
"name": "小明",
"age": 20,
"score": 95
}
# 直接赋值修改
student["age"] = 21
student["score"] = 98
print(student) # 输出:{'name': '小明', 'age': 21, 'score': 98}
# 使用update()修改多个值
student.update({"age": 22, "score": 100})
print(student) # 输出:{'name': '小明', 'age': 22, 'score': 100}
4. 查询元素
python
student = {
"name": "小明",
"age": 20,
"score": 95
}
# 获取所有键
print(student.keys()) # 输出:dict_keys(['name', 'age', 'score'])
print(list(student.keys())) # 输出:['name', 'age', 'score']
# 获取所有值
print(student.values()) # 输出:dict_values(['小明', 20, 95])
print(list(student.values())) # 输出:['小明', 20, 95]
# 获取所有键值对
print(student.items()) # 输出:dict_items([('name', '小明'), ('age', 20), ('score', 95)])
print(list(student.items())) # 输出:[('name', '小明'), ('age', 20), ('score', 95)]
# 判断键是否存在
print("name" in student) # 输出:True
print("gender" in student) # 输出:False
# 遍历字典
print("\n遍历键:")
for key in student:
print(key)
print("\n遍历值:")
for value in student.values():
print(value)
print("\n遍历键值对:")
for key, value in student.items():
print(f"{key}: {value}")
5. 字典推导式
python
# 基本语法:{键表达式: 值表达式 for 变量 in 序列}
# 创建1到5的平方字典
squares = {x: x**2 for x in range(1, 6)}
print(squares) # 输出:{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# 从列表创建字典
names = ["张三", "李四", "王五"]
ages = [20, 21, 22]
student_dict = {name: age for name, age in zip(names, ages)}
print(student_dict) # 输出:{'张三': 20, '李四': 21, '王五': 22}
# 筛选字典
scores = {"张三": 85, "李四": 92, "王五": 78, "赵六": 95}
high_scores = {name: score for name, score in scores.items() if score >= 90}
print(high_scores) # 输出:{'李四': 92, '赵六': 95}
# 键值反转
original = {"a": 1, "b": 2, "c": 3}
reversed_dict = {value: key for key, value in original.items()}
print(reversed_dict) # 输出:{1: 'a', 2: 'b', 3: 'c'}
三、嵌套字典
1. 字典嵌套字典
python
# 学生信息
students = {
"001": {
"name": "张三",
"age": 20,
"scores": {
"math": 85,
"english": 92,
"python": 95
}
},
"002": {
"name": "李四",
"age": 21,
"scores": {
"math": 78,
"english": 88,
"python": 90
}
}
}
# 访问嵌套字典
print(students["001"]["name"]) # 输出:张三
print(students["001"]["scores"]["python"]) # 输出:95
# 修改嵌套字典
students["001"]["scores"]["python"] = 98
print(students["001"]["scores"]["python"]) # 输出:98
# 添加新的学生
students["003"] = {
"name": "王五",
"age": 22,
"scores": {
"math": 90,
"english": 85,
"python": 92
}
}
# 遍历嵌套字典
for student_id, info in students.items():
print(f"学号:{student_id}")
print(f"姓名:{info['name']}")
print(f"年龄:{info['age']}")
print("成绩:")
for subject, score in info['scores'].items():
print(f" {subject}: {score}")
print()
2. 字典嵌套列表
python
# 班级信息
classes = {
"一班": {
"students": ["张三", "李四", "王五"],
"teacher": "刘老师"
},
"二班": {
"students": ["赵六", "钱七", "孙八"],
"teacher": "陈老师"
}
}
# 访问
print(classes["一班"]["students"]) # 输出:['张三', '李四', '王五']
print(classes["一班"]["students"][0]) # 输出:张三
# 添加学生
classes["一班"]["students"].append("小明")
print(classes["一班"]["students"]) # 输出:['张三', '李四', '王五', '小明']
四、集合的基本操作
1. 什么是集合
集合 是一个无序、不重复的元素集,用花括号 {} 表示。
python
# 创建集合
fruits = {"苹果", "香蕉", "橙子", "苹果"}
print(fruits) # 输出:{'苹果', '香蕉', '橙子'}(自动去重)
# 空集合(注意:{}创建的是空字典,不是空集合)
empty_set = set()
print(empty_set) # 输出:set()
# 使用set()函数创建
numbers = set([1, 2, 3, 2, 1])
print(numbers) # 输出:{1, 2, 3}
# 从字符串创建
chars = set("hello")
print(chars) # 输出:{'h', 'e', 'l', 'o'}
💡 提示:集合中的元素必须是不可变类型(如数字、字符串、元组)。
2. 集合的基本操作
python
fruits = {"苹果", "香蕉", "橙子"}
# 添加元素
fruits.add("葡萄")
print(fruits) # 输出:{'苹果', '香蕉', '橙子', '葡萄'}
# 添加多个元素
fruits.update(["西瓜", "芒果"])
print(fruits) # 输出:{'苹果', '香蕉', '橙子', '葡萄', '西瓜', '芒果'}
# 删除元素
fruits.remove("香蕉") # 元素不存在会报错
print(fruits) # 输出:{'苹果', '橙子', '葡萄', '西瓜', '芒果'}
fruits.discard("芒果") # 元素不存在不会报错
print(fruits) # 输出:{'苹果', '橙子', '葡萄', '西瓜'}
# pop()删除并返回一个元素
removed = fruits.pop()
print(removed) # 输出:苹果(随机)
print(fruits) # 输出:{'橙子', '葡萄', '西瓜'}
# 清空集合
fruits.clear()
print(fruits) # 输出:set()
3. 集合运算
python
set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}
# 交集(两个集合都有的元素)
print(set1 & set2) # 输出:{4, 5}
print(set1.intersection(set2)) # 输出:{4, 5}
# 并集(两个集合的所有元素,去重)
print(set1 | set2) # 输出:{1, 2, 3, 4, 5, 6, 7, 8}
print(set1.union(set2)) # 输出:{1, 2, 3, 4, 5, 6, 7, 8}
# 差集(set1有但set2没有的元素)
print(set1 - set2) # 输出:{1, 2, 3}
print(set1.difference(set2)) # 输出:{1, 2, 3}
# 对称差集(两个集合中不共有的元素)
print(set1 ^ set2) # 输出:{1, 2, 3, 6, 7, 8}
print(set1.symmetric_difference(set2)) # 输出:{1, 2, 3, 6, 7, 8}
4. 集合的比较
python
set1 = {1, 2, 3}
set2 = {1, 2, 3, 4, 5}
set3 = {1, 2, 3}
# 子集(set1是否是set2的子集)
print(set1 <= set2) # 输出:True
print(set1.issubset(set2)) # 输出:True
# 超集(set2是否是set1的超集)
print(set2 >= set1) # 输出:True
print(set2.issuperset(set1)) # 输出:True
# 真子集(set1是set2的子集,但不相等)
print(set1 < set2) # 输出:True
print(set1 < set3) # 输出:False(相等,不是真子集)
# 相等
print(set1 == set3) # 输出:True
5. 集合推导式
python
# 基本语法:{表达式 for 变量 in 序列}
# 创建平方集合
squares = {x**2 for x in range(1, 6)}
print(squares) # 输出:{1, 4, 9, 16, 25}
# 从列表创建集合(去重)
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unique_squares = {x**2 for x in numbers}
print(unique_squares) # 输出:{1, 4, 9, 16}
# 筛选集合
numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
evens = {x for x in numbers if x % 2 == 0}
print(evens) # 输出:{2, 4, 6, 8, 10}
五、字典与集合的应用
1. 字典的应用场景
python
# 1. 统计词频
text = "hello world hello python world hello"
words = text.split()
word_count = {}
for word in words:
if word in word_count:
word_count[word] += 1
else:
word_count[word] = 1
print(word_count) # 输出:{'hello': 3, 'world': 2, 'python': 1}
# 使用get()简化
word_count = {}
for word in words:
word_count[word] = word_count.get(word, 0) + 1
print(word_count) # 输出:{'hello': 3, 'world': 2, 'python': 1}
# 2. 缓存/记忆化
cache = {}
def fibonacci(n):
if n in cache:
return cache[n]
if n <= 1:
result = n
else:
result = fibonacci(n-1) + fibonacci(n-2)
cache[n] = result
return result
print(fibonacci(10)) # 输出:55
# 3. 配置管理
config = {
"database": {
"host": "localhost",
"port": 3306,
"user": "root",
"password": "123456"
},
"server": {
"host": "0.0.0.0",
"port": 8080
}
}
# 4. JSON数据处理
import json
data = {
"name": "小明",
"age": 20,
"scores": [85, 92, 95]
}
# 字典转JSON字符串
json_str = json.dumps(data, ensure_ascii=False, indent=2)
print(json_str)
# JSON字符串转字典
parsed_data = json.loads(json_str)
print(parsed_data)
2. 集合的应用场景
python
# 1. 去重
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unique_numbers = list(set(numbers))
print(unique_numbers) # 输出:[1, 2, 3, 4]
# 2. 判断成员关系(比列表快)
valid_users = {"user1", "user2", "user3", "user4", "user5"}
print("user1" in valid_users) # 输出:True(O(1)时间复杂度)
# 3. 找出两个列表的共同元素
list1 = [1, 2, 3, 4, 5]
list2 = [4, 5, 6, 7, 8]
common = set(list1) & set(list2)
print(common) # 输出:{4, 5}
# 4. 找出两个列表的不同元素
diff = set(list1) ^ set(list2)
print(diff) # 输出:{1, 2, 3, 6, 7, 8}
# 5. 合并多个列表并去重
list1 = [1, 2, 3]
list2 = [2, 3, 4]
list3 = [3, 4, 5]
merged = list(set(list1) | set(list2) | set(list3))
print(merged) # 输出:[1, 2, 3, 4, 5]
六、实战练习
练习1:学生成绩管理系统
python
# 学生成绩字典
students = {
"001": {"name": "张三", "scores": {"math": 85, "english": 92, "python": 95}},
"002": {"name": "李四", "scores": {"math": 78, "english": 88, "python": 90}},
"003": {"name": "王五", "scores": {"math": 90, "english": 85, "python": 92}}
}
# 计算每个学生的平均分
for student_id, info in students.items():
scores = info["scores"].values()
average = sum(scores) / len(scores)
print(f"{info['name']}的平均分:{average:.1f}")
# 找出Python成绩最高的学生
max_score = 0
top_student = ""
for student_id, info in students.items():
if info["scores"]["python"] > max_score:
max_score = info["scores"]["python"]
top_student = info["name"]
print(f"\nPython成绩最高:{top_student}({max_score}分)")
# 统计各科平均分
subjects = ["math", "english", "python"]
for subject in subjects:
scores = [info["scores"][subject] for info in students.values()]
average = sum(scores) / len(scores)
print(f"{subject}平均分:{average:.1f}")
练习2:词频统计
python
# 文本
text = """
Python是一种广泛使用的高级编程语言。
Python的设计哲学强调代码的可读性和简洁的语法。
Python支持多种编程范式,包括面向对象、命令式、函数式和过程式编程。
Python被广泛应用于Web开发、数据科学、人工智能等领域。
"""
# 清理文本
text = text.replace("。", "").replace(",", "").replace("、", "")
words = text.split()
# 统计词频
word_count = {}
for word in words:
word_count[word] = word_count.get(word, 0) + 1
# 按频率排序
sorted_words = sorted(word_count.items(), key=lambda x: x[1], reverse=True)
print("词频统计(前10):")
for word, count in sorted_words[:10]:
print(f"{word}:{count}次")
# 找出出现次数最多的词
most_common = sorted_words[0]
print(f"\n出现最多的词:{most_common[0]}({most_common[1]}次)")
练习3:集合运算应用
python
# 两个班级的学生名单
class1 = {"张三", "李四", "王五", "赵六", "钱七"}
class2 = {"孙八", "周九", "吴十", "赵六", "钱七"}
# 1. 找出两个班级都有的学生(可能转班)
common_students = class1 & class2
print(f"两个班级都有的学生:{common_students}")
# 2. 找出一班独有的学生
class1_only = class1 - class2
print(f"一班独有的学生:{class1_only}")
# 3. 找出所有学生(去重)
all_students = class1 | class2
print(f"所有学生:{all_students}")
print(f"总人数:{len(all_students)}")
# 4. 找出只在其中一个班级的学生
unique_students = class1 ^ class2
print(f"只在一个班级的学生:{unique_students}")
练习4:JSON数据处理
python
import json
# 模拟从API获取的数据
api_response = """
{
"status": "success",
"data": {
"users": [
{"id": 1, "name": "张三", "age": 20, "city": "北京"},
{"id": 2, "name": "李四", "age": 25, "city": "上海"},
{"id": 3, "name": "王五", "age": 22, "city": "广州"}
],
"total": 3
}
}
"""
# 解析JSON
data = json.loads(api_response)
# 提取用户信息
users = data["data"]["users"]
# 1. 打印所有用户信息
print("用户列表:")
for user in users:
print(f"ID: {user['id']}, 姓名: {user['name']}, 年龄: {user['age']}, 城市: {user['city']}")
# 2. 找出年龄最大的用户
oldest_user = max(users, key=lambda x: x["age"])
print(f"\n年龄最大的用户:{oldest_user['name']}({oldest_user['age']}岁)")
# 3. 统计各城市用户数
city_count = {}
for user in users:
city = user["city"]
city_count[city] = city_count.get(city, 0) + 1
print("\n各城市用户数:")
for city, count in city_count.items():
print(f"{city}:{count}人")
# 4. 将处理后的数据保存为JSON
result = {
"status": "success",
"oldest_user": oldest_user,
"city_count": city_count
}
result_json = json.dumps(result, ensure_ascii=False, indent=2)
print("\n处理结果:")
print(result_json)
七、常见问题与排错
问题1:字典键不存在报错
原因 :使用 [] 访问不存在的键 解决方法 :使用 get() 方法或先判断键是否存在
python
student = {"name": "小明", "age": 20}
# ❌ 错误
# print(student["gender"]) # KeyError: 'gender'
# ✅ 正确方法1:使用get()
print(student.get("gender", "未知")) # 输出:未知
# ✅ 正确方法2:先判断
if "gender" in student:
print(student["gender"])
else:
print("未知")
问题2:修改字典时迭代报错
原因 :在遍历字典时修改字典 解决方法:先收集要修改的键,遍历完再修改
python
student = {"name": "小明", "age": 20, "score": 95}
# ❌ 错误:在遍历时修改字典
# for key in student:
# if key == "age":
# del student[key] # RuntimeError: dictionary changed size during iteration
# ✅ 正确:先收集要删除的键
keys_to_delete = []
for key in student:
if key == "age":
keys_to_delete.append(key)
for key in keys_to_delete:
del student[key]
print(student) # 输出:{'name': '小明', 'score': 95}
问题3:集合元素不可变
原因 :集合的元素必须是不可变类型 解决方法:使用元组代替列表
python
# ❌ 错误:列表不能作为集合元素
# invalid_set = {[1, 2], [3, 4]} # TypeError: unhashable type: 'list'
# ✅ 正确:使用元组
valid_set = {(1, 2), (3, 4)}
print(valid_set) # 输出:{(1, 2), (3, 4)}
八、本篇小结
今天,我们完成了以下学习内容:
-
字典的键值对:
- 使用
{}或dict()创建字典 - 键必须是不可变类型,值可以是任意类型
- 通过键访问值,使用
get()更安全
- 使用
-
字典的增删改查:
- 增加:直接赋值、
update() - 删除:
del、pop()、popitem()、clear() - 修改:直接赋值、
update() - 查询:
keys()、values()、items()、遍历
- 增加:直接赋值、
-
集合的基本操作:
- 使用
{}或set()创建集合 - 添加:
add()、update() - 删除:
remove()、discard()、pop()、clear() - 集合运算:交集、并集、差集、对称差集
- 使用
请记住这三个结论:
- 字典通过键查找值:适合存储有对应关系的数据
- 集合自动去重:适合存储不重复的元素,支持集合运算
- 字典和集合查找速度快:时间复杂度为O(1)
下期预告
在第8期中,我们将学习Python的函数,包括:
- 函数的定义和调用
- 参数和返回值
- 变量的作用域
- 匿名函数和高阶函数
敬请期待!
✍坚持原创,求关注,点赞,收藏