在前面的章节中,我们学习了Python的基本语法、数据类型和流程控制语句。本章将深入探讨Python的数据结构,包括列表(List)、元组(Tuple)、字典(Dictionary)、集合(Set)以及字符串的处理。这些数据结构是Python编程的基础,掌握它们对于编写高效的Python程序至关重要。
列表是Python中最常用的数据结构之一,它是一个可变的、有序的元素集合。
生活类比: 列表就像一个有序的购物清单或待办事项列表,你可以随时查看、添加、修改或删除其中的项目。
可以使用方括号 []
创建列表,各元素之间用逗号分隔:
# 创建空列表
empty_list = []
# 创建包含元素的列表
numbers = [1, 2, 3, 4, 5]
fruits = ["苹果", "香蕉", "橙子"]
mixed = [1, "hello", 3.14, True] # 列表可以包含不同类型的元素
也可以使用 list()
函数将其他可迭代对象转换为列表:
# 从字符串创建列表
chars = list("Python") # 结果: ['P', 'y', 't', 'h', 'o', 'n']
# 从range创建列表
numbers = list(range(1, 6)) # 结果: [1, 2, 3, 4, 5]
实用场景: 创建用户信息列表
# 存储系统中的用户信息 users = [ ["张三", 28, "北京", "工程师"], ["李四", 35, "上海", "设计师"], ["王五", 22, "广州", "学生"] ] # 存储接口返回的JSON数据 api_response = [ {"id": 1, "name": "产品A", "price": 99.9}, {"id": 2, "name": "产品B", "price": 199.5}, {"id": 3, "name": "产品C", "price": 299.0} ]
可以使用索引来访问列表中的元素。Python的索引从0开始:
fruits = ["苹果", "香蕉", "橙子", "葡萄", "西瓜"]
# 使用正索引(从0开始)
print(fruits[0]) # 输出: 苹果
print(fruits[2]) # 输出: 橙子
# 使用负索引(从-1开始,表示从末尾开始计数)
print(fruits[-1]) # 输出: 西瓜
print(fruits[-3]) # 输出: 橙子
索引可视化:
索引: 0 1 2 3 4 正向: ["苹果", "香蕉", "橙子", "葡萄", "西瓜"] 反向: -5 -4 -3 -2 -1
实用场景: 访问列表中的最新消息或最后添加的元素
# 获取最新消息 messages = ["早上好", "会议改期了", "项目已完成", "新任务已分配"] latest_message = messages[-1] print(f"最新消息: {latest_message}") # 输出: 最新消息: 新任务已分配 # 获取最近三条消息 recent_messages = messages[-3:] for msg in recent_messages: print(f"- {msg}")
通过切片操作可以获取列表的一部分:
fruits = ["苹果", "香蕉", "橙子", "葡萄", "西瓜"]
# 基本切片语法:list[start:end],包括start,不包括end
print(fruits[1:4]) # 输出: ['香蕉', '橙子', '葡萄']
# 省略start,默认从0开始
print(fruits[:3]) # 输出: ['苹果', '香蕉', '橙子']
# 省略end,默认到列表末尾
print(fruits[2:]) # 输出: ['橙子', '葡萄', '西瓜']
# 使用负索引进行切片
print(fruits[-3:-1]) # 输出: ['橙子', '葡萄']
# 设置步长(第三个参数)
print(fruits[::2]) # 输出: ['苹果', '橙子', '西瓜'],步长为2
# 反转列表
print(fruits[::-1]) # 输出: ['西瓜', '葡萄', '橙子', '香蕉', '苹果']
切片可视化:
fruits[1:4] 获取索引1到3的元素(不包括4): ["苹果", "香蕉", "橙子", "葡萄", "西瓜"] ↑ ↑ ↑ 包括 包括 包括
实用场景: 分页显示数据
# 模拟数据库查询返回的结果 all_products = ["手机", "电脑", "平板", "耳机", "相机", "手表", "键盘", "鼠标", "显示器", "打印机"] # 每页显示3个商品 page_size = 3 # 显示第1页(索引0-2) page1 = all_products[:page_size] print("第1页:", page1) # 输出: 第1页: ['手机', '电脑', '平板'] # 显示第2页(索引3-5) page2 = all_products[page_size:page_size*2] print("第2页:", page2) # 输出: 第2页: ['耳机', '相机', '手表'] # 函数实现任意页的获取 def get_page(items, page_number, items_per_page): start = (page_number - 1) * items_per_page end = start + items_per_page return items[start:end] # 获取第3页 page3 = get_page(all_products, 3, page_size) print("第3页:", page3) # 输出: 第3页: ['键盘', '鼠标', '显示器']
列表是可变的,可以修改其元素:
fruits = ["苹果", "香蕉", "橙子"]
# 修改单个元素
fruits[1] = "梨"
print(fruits) # 输出: ['苹果', '梨', '橙子']
# 使用切片修改多个元素
fruits[0:2] = ["草莓", "蓝莓"]
print(fruits) # 输出: ['草莓', '蓝莓', '橙子']
实用场景: 更新购物车
# 购物车商品和数量 cart = [["笔记本电脑", 1], ["鼠标", 2], ["键盘", 1]] # 客户将键盘数量改为2 cart[2][1] = 2 print("更新后的购物车:") for item, quantity in cart: print(f"- {item}: {quantity}个") # 客户将笔记本电脑和鼠标换成了其他型号 cart[0:2] = [["游戏本", 1], ["无线鼠标", 1]] print("\n更换商品后的购物车:") for item, quantity in cart: print(f"- {item}: {quantity}个")
以下是一些常用的列表操作:
fruits = ["苹果", "香蕉", "橙子"]
# 添加元素到列表末尾
fruits.append("葡萄")
print(fruits) # 输出: ['苹果', '香蕉', '橙子', '葡萄']
# 在指定位置插入元素
fruits.insert(1, "梨")
print(fruits) # 输出: ['苹果', '梨', '香蕉', '橙子', '葡萄']
# 合并两个列表
more_fruits = ["西瓜", "芒果"]
fruits.extend(more_fruits)
print(fruits) # 输出: ['苹果', '梨', '香蕉', '橙子', '葡萄', '西瓜', '芒果']
# 也可以使用 + 运算符
fruits = fruits + ["哈密瓜"]
print(fruits) # 输出: ['苹果', '梨', '香蕉', '橙子', '葡萄', '西瓜', '芒果', '哈密瓜']
# 移除指定元素
fruits.remove("香蕉")
print(fruits) # 输出: ['苹果', '梨', '橙子', '葡萄', '西瓜', '芒果', '哈密瓜']
# 移除并返回指定位置的元素
popped = fruits.pop(2) # 移除位置2的元素(即"橙子")
print(popped) # 输出: 橙子
print(fruits) # 输出: ['苹果', '梨', '葡萄', '西瓜', '芒果', '哈密瓜']
# 如果不指定索引,pop()将移除并返回最后一个元素
popped = fruits.pop()
print(popped) # 输出: 哈密瓜
print(fruits) # 输出: ['苹果', '梨', '葡萄', '西瓜', '芒果']
# 查找元素的索引
index = fruits.index("葡萄")
print(index) # 输出: 2
# 元素出现的次数
fruits.append("梨")
count = fruits.count("梨")
print(count) # 输出: 2
# 排序列表
fruits.sort()
print(fruits) # 输出: ['梨', '梨', '苹果', '葡萄', '西瓜', '芒果'](按中文拼音排序)
numbers = [5, 2, 8, 1, 9]
numbers.sort()
print(numbers) # 输出: [1, 2, 5, 8, 9]
# 逆序排列
fruits.reverse()
print(fruits) # 输出: ['芒果', '西瓜', '葡萄', '苹果', '梨', '梨']
# 清空列表
fruits.clear()
print(fruits) # 输出: []
列表方法备忘录:
方法 功能 例子 append()
在列表末尾添加元素 fruits.append("葡萄")
insert()
在指定位置插入元素 fruits.insert(1, "梨")
extend()
合并另一个列表到末尾 fruits.extend(more_fruits)
remove()
移除指定元素 fruits.remove("香蕉")
pop()
移除并返回指定位置元素 fruit = fruits.pop(2)
index()
查找元素的索引 idx = fruits.index("葡萄")
count()
统计元素出现次数 n = fruits.count("梨")
sort()
排序列表 fruits.sort()
reverse()
反转列表 fruits.reverse()
clear()
清空列表 fruits.clear()
实用场景: 任务管理应用
# 任务管理系统 tasks = [] # 添加任务 tasks.append("完成Python作业") tasks.append("准备周会演讲") tasks.append("购买生日礼物") print("当前任务:", tasks) # 插入高优先级任务 tasks.insert(0, "回复紧急邮件") print("添加紧急任务后:", tasks) # 完成任务 completed_task = tasks.pop(0) # 完成第一个任务 print(f"已完成: {completed_task}") print("剩余任务:", tasks) # 添加多个任务 new_tasks = ["整理文件", "预约医生"] tasks.extend(new_tasks) print("添加新任务后:", tasks) # 取消任务 tasks.remove("购买生日礼物") print("取消购物任务后:", tasks) # 按字母顺序排序任务 tasks.sort() print("任务排序后:", tasks)
列表推导式是一种简洁而强大的创建列表的方式:
# 基本语法: [expression for item in iterable]
squares = [x ** 2 for x in range(1, 6)]
print(squares) # 输出: [1, 4, 9, 16, 25]
# 带条件的列表推导式: [expression for item in iterable if condition]
even_squares = [x ** 2 for x in range(1, 11) if x % 2 == 0]
print(even_squares) # 输出: [4, 16, 36, 64, 100]
# 多层列表推导式
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [x for row in matrix for x in row]
print(flattened) # 输出: [1, 2, 3, 4, 5, 6, 7, 8, 9]
列表推导式与传统循环对比:
传统方法:
# 求平方 squares = [] for x in range(1, 6): squares.append(x ** 2)
列表推导式:
# 求平方 squares = [x ** 2 for x in range(1, 6)]
实用场景: 数据转换和筛选
# 商品数据 products = [ {"id": 1, "name": "笔记本电脑", "price": 5999, "stock": 10}, {"id": 2, "name": "鼠标", "price": 109, "stock": 0}, {"id": 3, "name": "键盘", "price": 329, "stock": 5}, {"id": 4, "name": "显示器", "price": 1299, "stock": 3}, {"id": 5, "name": "耳机", "price": 599, "stock": 0}, ] # 提取所有商品名称 product_names = [p["name"] for p in products] print("所有商品:", product_names) # 筛选有库存的商品 in_stock = [p["name"] for p in products if p["stock"] > 0] print("有库存商品:", in_stock) # 价格大于1000元的商品及其价格 expensive_products = [(p["name"], p["price"]) for p in products if p["price"] > 1000] print("高价商品:") for name, price in expensive_products: print(f"- {name}: ¥{price}") # 所有商品的总价值 (价格 × 库存) total_value = sum([p["price"] * p["stock"] for p in products]) print(f"库存总价值: ¥{total_value}")
元组是不可变的有序序列,一旦创建就不能修改。
生活类比: 元组就像是密封的包装盒,一旦包装好就不能更改里面的内容。适合存储那些不应该被修改的数据,比如一周的天数或RGB颜色值。
可以使用圆括号 ()
创建元组,各元素之间用逗号分隔:
# 创建空元组
empty_tuple = ()
# 创建包含元素的元组
numbers = (1, 2, 3, 4, 5)
fruits = ("苹果", "香蕉", "橙子")
mixed = (1, "hello", 3.14, True)
# 注意:创建只有一个元素的元组时,需要在元素后加逗号
single_item = (42,) # 这是一个元组
not_tuple = (42) # 这不是元组,而是一个整数
也可以使用 tuple()
函数将其他可迭代对象转换为元组:
# 从列表创建元组
tuple_from_list = tuple([1, 2, 3])
print(tuple_from_list) # 输出: (1, 2, 3)
# 从字符串创建元组
chars = tuple("Python")
print(chars) # 输出: ('P', 'y', 't', 'h', 'o', 'n')
实用场景: 使用元组存储不变的数据
# RGB颜色值 red = (255, 0, 0) green = (0, 255, 0) blue = (0, 0, 255) # 存储坐标 point_2d = (10.5, 20.8) point_3d = (10.5, 20.8, 15.2) # 固定选项 available_sizes = ("S", "M", "L", "XL") # 存储记录 employee = ("张三", "IT部门", "工程师", 35000) name, department, position, salary = employee # 元组解包 print(f"{name}是{department}的{position},月薪{salary}元")
与列表类似,可以使用索引访问元组元素:
fruits = ("苹果", "香蕉", "橙子", "葡萄", "西瓜")
# 使用索引
print(fruits[0]) # 输出: 苹果
print(fruits[-1]) # 输出: 西瓜
# 使用切片
print(fruits[1:4]) # 输出: ('香蕉', '橙子', '葡萄')
一旦创建,元组的元素不能被修改:
fruits = ("苹果", "香蕉", "橙子")
# 尝试修改元组元素会导致错误
# fruits[0] = "梨" # 这会引发TypeError
# 但如果元组包含可变对象(如列表),那么可变对象的内容可以修改
t = (1, 2, [3, 4])
t[2][0] = 5
print(t) # 输出: (1, 2, [5, 4])
提示: 元组的不可变性使其成为字典键和集合元素的理想选择,因为这些结构要求键/元素是不可变的。
实用场景: 使用元组作为函数返回多个值
# 函数返回多个值(作为元组) def get_user_stats(user_id): # 假设这是从数据库获取的数据 name = "张三" posts = 42 followers = 1024 following = 128 return name, posts, followers, following # 自动打包为元组 # 调用函数并解包返回值 user_name, post_count, follower_count, following_count = get_user_stats(12345) print(f"用户: {user_name}") print(f"帖子数: {post_count}") print(f"粉丝数: {follower_count}") print(f"关注数: {following_count}") # 或者直接获取元组 stats = get_user_stats(12345) print(f"用户 {stats[0]} 有 {stats[2]} 个粉丝")
# 合并元组
t1 = (1, 2, 3)
t2 = (4, 5, 6)
t3 = t1 + t2
print(t3) # 输出: (1, 2, 3, 4, 5, 6)
# 重复元组
repeated = t1 * 3
print(repeated) # 输出: (1, 2, 3, 1, 2, 3, 1, 2, 3)
# 检查元素是否在元组中
print("苹果" in fruits) # 输出: True
print("梨" in fruits) # 输出: False
# 获取元组长度
print(len(fruits)) # 输出: 5
# 获取元素出现的次数
numbers = (1, 2, 3, 2, 1, 4, 2)
print(numbers.count(2)) # 输出: 3
# 查找元素第一次出现的索引
print(numbers.index(3)) # 输出: 2
列表vs元组: 何时使用哪个?
列表 元组 可变(可修改内容) 不可变(内容固定) 适用于需要增删改的数据集合 适用于固定不变的数据集合 例如:购物车商品、任务列表 例如:RGB颜色值、坐标点、配置选项 稍微占用更多内存 内存使用更高效 不能作为字典键 可以作为字典键
实用场景: 使用元组作为字典键
# 存储不同城市不同月份的天气数据 # (城市, 月份) -> 温度 weather_data = { ("北京", "一月"): 0, ("北京", "七月"): 30, ("上海", "一月"): 7, ("上海", "七月"): 32, ("广州", "一月"): 14, ("广州", "七月"): 29 } # 查询特定城市和月份的天气 city = "北京" month = "七月" temperature = weather_data[(city, month)] print(f"{city}在{month}的平均温度是{temperature}℃") # 遍历所有数据 for (city, month), temp in weather_data.items(): print(f"{city}在{month}的平均温度是{temp}℃")
字典是一种可变的、无序的数据结构,它存储键值对。字典中的每个键必须是唯一的,且必须是不可变类型(如字符串、数字、元组)。
生活类比: 字典就像通讯录,你可以通过人名(键)快速找到对应的电话号码(值),而不必从头到尾翻阅整个通讯录。
可以使用花括号 {}
创建字典,各键值对之间用逗号分隔,键和值之间用冒号 :
分隔:
# 创建空字典
empty_dict = {}
# 创建包含键值对的字典
person = {
"name": "张三",
"age": 30,
"city": "北京"
}
# 使用dict()函数创建字典
person = dict(name="张三", age=30, city="北京")
实用场景: 存储用户信息
# 用户个人资料 user_profile = { "username": "zhang_san", "email": "[email protected]", "name": "张三", "age": 28, "is_active": True, "interests": ["编程", "阅读", "旅行"], "address": { "city": "北京", "district": "海淀", "street": "中关村大街" } } # 产品目录 products = { "A001": {"name": "笔记本电脑", "price": 5999, "stock": 10}, "A002": {"name": "鼠标", "price": 109, "stock": 50}, "A003": {"name": "键盘", "price": 329, "stock": 30} }
可以使用键来访问字典中的值:
person = {"name": "张三", "age": 30, "city": "北京"}
# 使用键访问值
print(person["name"]) # 输出: 张三
# 使用get()方法访问值(推荐方式,可以设置默认值)
print(person.get("age")) # 输出: 30
print(person.get("email")) # 输出: None(因为键不存在)
print(person.get("email", "未设置")) # 输出: 未设置(使用默认值)
注意: 如果使用中括号语法访问不存在的键,会引发KeyError错误。而使用get()方法则会返回None或指定的默认值。
实用场景: 显示用户信息
# 从数据库获取的用户信息(可能缺少某些字段) user = { "user_id": 12345, "username": "zhang_san", "name": "张三" # 可能没有email、phone等字段 } # 安全地获取用户信息 print(f"用户ID: {user['user_id']}") print(f"用户名: {user['username']}") print(f"姓名: {user.get('name', '未提供')}") print(f"邮箱: {user.get('email', '未提供')}") print(f"电话: {user.get('phone', '未提供')}") # 使用字典作为简单数据库 product_id = "A002" if product_id in products: product = products[product_id] print(f"商品: {product['name']}") print(f"价格: ¥{product['price']}") print(f"库存: {product['stock']}件") else: print(f"商品 {product_id} 不存在")
字典是可变的,可以添加、修改和删除键值对:
person = {"name": "张三", "age": 30, "city": "北京"}
# 修改值
person["age"] = 31
print(person) # 输出: {'name': '张三', 'age': 31, 'city': '北京'}
# 添加新的键值对
person["email"] = "[email protected]"
print(person) # 输出: {'name': '张三', 'age': 31, 'city': '北京', 'email': '[email protected]'}
# 删除键值对
del person["city"]
print(person) # 输出: {'name': '张三', 'age': 31, 'email': '[email protected]'}
# 使用pop()方法删除并返回值
email = person.pop("email")
print(email) # 输出: [email protected]
print(person) # 输出: {'name': '张三', 'age': 31}
# 清空字典
person.clear()
print(person) # 输出: {}
实用场景: 更新用户信息
# 当前用户信息 user = { "username": "zhang_san", "email": "[email protected]", "phone": "13800138000", "address": "北京市海淀区" } # 用户提交的更新信息(部分字段) update_data = { "email": "[email protected]", "address": "上海市浦东新区" } # 更新用户信息 for key, value in update_data.items(): user[key] = value print("更新后的用户信息:") for key, value in user.items(): print(f"{key}: {value}") # 更简洁的方式:使用update()方法 user = { "username": "zhang_san", "email": "[email protected]", "phone": "13800138000", "address": "北京市海淀区" } user.update(update_data) print("使用update()更新后:") for key, value in user.items(): print(f"{key}: {value}")
Python字典提供了许多有用的方法:
person = {
"name": "张三",
"age": 30,
"city": "北京",
"email": "[email protected]"
}
# 获取所有键
keys = person.keys()
print(keys) # 输出: dict_keys(['name', 'age', 'city', 'email'])
# 获取所有值
values = person.values()
print(values) # 输出: dict_values(['张三', 30, '北京', '[email protected]'])
# 获取所有键值对
items = person.items()
print(items) # 输出: dict_items([('name', '张三'), ('age', 30), ('city', '北京'), ('email', '[email protected]')])
# 使用update()方法更新字典
person.update({"age": 31, "phone": "13800138000"})
print(person) # 输出更新后的字典
# 检查键是否存在
print("name" in person) # 输出: True
print("gender" in person) # 输出: False
# 使用setdefault()方法获取值,如果键不存在则设置默认值
gender = person.setdefault("gender", "男")
print(gender) # 输出: 男
print(person) # 输出: 包含新添加的gender键
字典方法备忘录:
方法 功能 例子 keys()
返回所有键 person.keys()
values()
返回所有值 person.values()
items()
返回所有键值对 person.items()
get()
获取值,可设置默认值 person.get("age", 0)
update()
更新字典 person.update({"age": 31})
pop()
删除并返回值 age = person.pop("age")
clear()
清空字典 person.clear()
setdefault()
获取值,不存在时设置 person.setdefault("gender", "男")
实用场景: 单词频率统计
text = """ Python是一种广泛使用的解释型、高级编程语言。Python支持多种编程范式, 包括面向对象、命令式、函数式和过程式编程。它拥有动态类型系统和垃圾回收功能, 能够自动管理内存使用,并且其本身拥有一个广泛的标准库。 """ # 将文本分割成单词 words = text.replace(",", "").replace("。", "").replace("\n", " ").split(" ") words = [word for word in words if word] # 移除空字符串 # 统计每个单词出现的次数 word_count = {} for word in words: # 如果单词已存在,次数加1;否则设为1 word_count[word] = word_count.get(word, 0) + 1 # 显示出现次数最多的5个单词 sorted_words = sorted(word_count.items(), key=lambda x: x[1], reverse=True) print("出现频率最高的单词:") for word, count in sorted_words[:5]: print(f"'{word}': {count}次")
类似于列表推导式,字典也有推导式语法:
# 从两个列表创建字典
keys = ["a", "b", "c", "d", "e"]
values = [1, 2, 3, 4, 5]
my_dict = {keys[i]: values[i] for i in range(len(keys))}
print(my_dict) # 输出: {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
# 带条件的字典推导式
original = {"a": 1, "b": 2, "c": 3, "d": 4, "e": 5}
even_dict = {k: v for k, v in original.items() if v % 2 == 0}
print(even_dict) # 输出: {'b': 2, 'd': 4}
# 转换值
squared = {k: v**2 for k, v in original.items()}
print(squared) # 输出: {'a': 1, 'b': 4, 'c': 9, 'd': 16, 'e': 25}
实用场景: 数据转换和过滤
# 原始学生成绩数据 scores = { "张三": 85, "李四": 92, "王五": 78, "赵六": 65, "钱七": 90 } # 转换成绩为等级 def score_to_grade(score): if score >= 90: return "A" elif score >= 80: return "B" elif score >= 70: return "C" elif score >= 60: return "D" else: return "F" # 使用字典推导式转换成绩为等级 grades = {name: score_to_grade(score) for name, score in scores.items()} print("学生成绩等级:") for name, grade in grades.items(): print(f"{name}: {grade}") # 筛选成绩优秀(≥90)的学生 excellent = {name: score for name, score in scores.items() if score >= 90} print("\n成绩优秀的学生:") for name, score in excellent.items(): print(f"{name}: {score}")
字典的值可以是任何类型,包括其他字典:
# 嵌套字典示例
students = {
"张三": {
"age": 20,
"major": "计算机科学",
"grades": {"数学": 90, "英语": 85, "编程": 95}
},
"李四": {
"age": 22,
"major": "数据科学",
"grades": {"数学": 95, "英语": 80, "编程": 90}
}
}
# 访问嵌套字典中的值
print(students["张三"]["grades"]["编程"]) # 输出: 95
# 修改嵌套字典中的值
students["李四"]["grades"]["英语"] = 85
# 添加新的嵌套数据
students["王五"] = {
"age": 21,
"major": "人工智能",
"grades": {"数学": 88, "英语": 90, "编程": 92}
}
实用场景: 构建产品目录
# 电子商务网站的产品目录 store = { "电子产品": { "手机": [ {"id": "P001", "name": "智能手机A", "price": 3999, "stock": 50}, {"id": "P002", "name": "智能手机B", "price": 4999, "stock": 30} ], "电脑": [ {"id": "C001", "name": "笔记本电脑X", "price": 5999, "stock": 20}, {"id": "C002", "name": "台式电脑Y", "price": 4599, "stock": 15} ] }, "服装": { "男装": [ {"id": "M001", "name": "男士T恤", "price": 99, "stock": 200}, {"id": "M002", "name": "男士牛仔裤", "price": 199, "stock": 150} ], "女装": [ {"id": "W001", "name": "女士连衣裙", "price": 299, "stock": 180}, {"id": "W002", "name": "女士外套", "price": 399, "stock": 120} ] } } # 遍历并显示所有产品 for category, subcategories in store.items(): print(f"【{category}】") for subcategory, products in subcategories.items(): print(f" {subcategory}:") for product in products: print(f" - {product['name']}: ¥{product['price']}, 库存: {product['stock']}件") # 查询特定产品 def find_product(product_id): for category, subcategories in store.items(): for subcategory, products in subcategories.items(): for product in products: if product['id'] == product_id: return product return None # 查找并显示产品信息 product = find_product("C001") if product: print(f"\n找到产品: {product['name']}, 价格: ¥{product['price']}") else: print("\n未找到该产品")
集合是一个无序的、不重复的元素集合。它在处理去重、成员检测和数学集合运算方面非常高效。
可以使用花括号 {}
创建集合(注意与字典的区别):
# 创建集合
fruits = {"苹果", "香蕉", "橙子"}
print(fruits) # 输出顺序可能不同,因为集合是无序的
# 使用set()函数创建集合
numbers = set([1, 2, 3, 2, 1]) # 重复元素会被自动去除
print(numbers) # 输出: {1, 2, 3}
# 创建空集合(注意:{}会创建空字典,而不是空集合)
empty_set = set()
print(type(empty_set)) # 输出:
print(type({})) # 输出:
fruits = {"苹果", "香蕉", "橙子"}
# 添加元素
fruits.add("葡萄")
print(fruits) # 输出: {'香蕉', '苹果', '橙子', '葡萄'}(顺序可能不同)
# 移除元素
fruits.remove("香蕉") # 如果元素不存在,会引发KeyError
print(fruits) # 输出: {'苹果', '橙子', '葡萄'}
# 移除元素,如果不存在也不会报错
fruits.discard("香蕉") # 不会引发错误,因为"香蕉"已经不在集合中了
# 随机移除并返回一个元素
popped = fruits.pop()
print(popped) # 输出随机的一个元素
print(fruits) # 原集合减少一个元素
# 清空集合
fruits.clear()
print(fruits) # 输出: set()
集合最常见的用途之一是去除重复项:
# 去除列表中的重复项
duplicate_list = [1, 2, 3, 1, 2, 5, 6, 7, 8, 6, 4]
unique_list = list(set(duplicate_list))
print(unique_list) # 输出: [1, 2, 3, 4, 5, 6, 7, 8](顺序可能不同)
# 去除字符串中的重复字符
text = "hello world"
unique_chars = ''.join(set(text))
print(unique_chars) # 输出: 'helowrd '(顺序可能不同)
# 注意:这种方法会打乱原始顺序。如果需要保持顺序,应使用其他方法。
集合的成员检测效率非常高,比列表快得多:
# 准备测试数据
large_list = list(range(10000))
large_set = set(range(10000))
# 测试不在集合中的元素
import time
# 列表查找
start = time.time()
if 10001 not in large_list:
pass
end = time.time()
print(f"列表查找耗时: {end - start:.6f}秒") # 输出类似: 列表查找耗时: 0.000412秒
# 集合查找
start = time.time()
if 10001 not in large_set:
pass
end = time.time()
print(f"集合查找耗时: {end - start:.6f}秒") # 输出类似: 集合查找耗时: 0.000021秒
# 假设有一个用户ID列表,我们需要过滤掉已注册的用户
all_users = [101, 102, 103, 104, 105, 106, 107]
registered_users = {101, 103, 105}
# 找出未注册的用户
unregistered_users = [user for user in all_users if user not in registered_users]
print(unregistered_users) # 输出: [102, 104, 106, 107]
# 更高效的方法是直接使用集合差集
unregistered_users = list(set(all_users) - registered_users)
print(unregistered_users) # 输出: [102, 104, 106, 107](顺序可能不同)
集合支持交集、并集、差集等数学运算,这些操作在数据处理中非常有用:
a = {1, 2, 3, 4, 5}
b = {4, 5, 6, 7, 8}
# 并集(所有不重复的元素)
union = a | b # 或者使用 a.union(b)
print(union) # 输出: {1, 2, 3, 4, 5, 6, 7, 8}
# 交集(共有的元素)
intersection = a & b # 或者使用 a.intersection(b)
print(intersection) # 输出: {4, 5}
# 差集(在a中但不在b中的元素)
difference = a - b # 或者使用 a.difference(b)
print(difference) # 输出: {1, 2, 3}
# 对称差集(在a或b中,但不同时在a和b中的元素)
symmetric_difference = a ^ b # 或者使用 a.symmetric_difference(b)
print(symmetric_difference) # 输出: {1, 2, 3, 6, 7, 8}
# 检查是否为子集/超集
c = {1, 2}
print(c.issubset(a)) # 输出: True,c是a的子集
print(a.issuperset(c)) # 输出: True,a是c的超集
# 一个简单的文章标签系统
articles = [
{"id": 1, "title": "Python入门", "tags": {"编程", "Python", "教程"}},
{"id": 2, "title": "数据分析基础", "tags": {"数据", "Python", "分析"}},
{"id": 3, "title": "Web开发入门", "tags": {"Web", "编程", "HTML"}}
]
# 查找所有与Python相关的文章
python_articles = [article for article in articles if "Python" in article["tags"]]
print("Python相关文章:")
for article in python_articles:
print(f"- {article['title']}")
# 查找同时包含"编程"和"Python"标签的文章
programming_and_python = [
article for article in articles
if {"编程", "Python"}.issubset(article["tags"])
]
print("\n既是编程又是Python的文章:")
for article in programming_and_python:
print(f"- {article['title']}")
# 查找所有使用的标签
all_tags = set()
for article in articles:
all_tags |= article["tags"] # 使用并集操作合并标签
print(f"\n所有标签: {all_tags}")
类似于列表推导式,Python也支持集合推导式:
# 基本语法: {expression for item in iterable if condition}
squares = {x**2 for x in range(1, 6)}
print(squares) # 输出: {1, 4, 9, 16, 25}
# 带条件的集合推导式
even_squares = {x**2 for x in range(1, 11) if x % 2 == 0}
print(even_squares) # 输出: {4, 16, 36, 64, 100}
# 实际应用:从文本中提取所有唯一单词
text = "Python是一种编程语言,Python简单易学,编程让生活更美好"
words = {word for word in text.replace(",", "").replace("。", "")}
print(words) # 输出所有唯一字符
虽然我们在基本数据类型章节已经介绍了字符串,但这里将更深入地讨论字符串的处理方法和实际应用场景。
# 字符串连接
first_name = "张"
last_name = "三"
full_name = first_name + last_name
print(full_name) # 输出: 张三
# 字符串重复
stars = "*" * 10
print(stars) # 输出: **********
print("-" * 30) # 输出30个连字符,常用于分隔线
# 字符串长度
length = len("Python")
print(length) # 输出: 6
# 字符串索引和切片
s = "Python编程"
print(s[0]) # 输出: P
print(s[-1]) # 输出: 程
print(s[0:6]) # 输出: Python
print(s[:6]) # 输出: Python(从开始到索引5)
print(s[6:]) # 输出: 编程(从索引6到结束)
# 字符串查找
text = "Python是一种流行的编程语言,Python易学易用。"
position = text.find("Python") # 找到第一个匹配的索引
print(position) # 输出: 0
position = text.find("Python", 1) # 从索引1开始查找
print(position) # 输出: 17
position = text.find("Java") # 不存在的字符串
print(position) # 输出: -1(表示未找到)
# 使用index()方法(与find类似,但找不到时会抛出异常)
try:
position = text.index("Java")
except ValueError:
print("未找到指定字符串")
# 检查字符串开头和结尾
print(text.startswith("Python")) # 输出: True
print(text.endswith("。")) # 输出: True
# 实用场景:检查文件类型
filename = "document.pdf"
if filename.endswith((".pdf", ".PDF")): # 可以传入元组检查多个后缀
print("这是PDF文件")
# 字符串替换
new_text = text.replace("Python", "JavaScript")
print(new_text) # 输出: JavaScript是一种流行的编程语言,JavaScript易学易用。
# 限制替换次数
new_text = text.replace("Python", "JavaScript", 1) # 只替换第一次出现
print(new_text) # 输出: JavaScript是一种流行的编程语言,Python易学易用。
# 计数
count = text.count("Python")
print(count) # 输出: 2
# 处理用户输入,去除多余空格
user_input = " Python 编程 "
cleaned_input = user_input.strip()
print(cleaned_input) # 输出: "Python 编程"
# 标准化文本(删除所有多余空格)
words = cleaned_input.split() # 按空格分割成单词列表
normalized_text = " ".join(words)
print(normalized_text) # 输出: "Python 编程"
# 文本转化:首字母大写
text = "python programming is fun"
print(text.title()) # 输出: "Python Programming Is Fun"
# 检查字符串内容
print("123".isdigit()) # 输出: True(是否全是数字)
print("Python3".isalnum()) # 输出: True(是否全是字母或数字)
print("Python".isalpha()) # 输出: True(是否全是字母)
print("PYTHON".isupper()) # 输出: True(是否全是大写)
print("python".islower()) # 输出: True(是否全是小写)
# 实际应用:验证用户输入
username = "user123"
if username.isalnum() and len(username) >= 5:
print("用户名有效")
else:
print("用户名无效:必须至少包含5个字母或数字")
Python提供了多种字符串格式化的方法:
name = "张三"
age = 25
height = 1.75
scores = {"语文": 85, "数学": 92, "英语": 78}
# 使用f-string(Python 3.6+,推荐使用)
formatted = f"我叫{name},今年{age}岁,身高{height:.2f}米。"
print(formatted) # 输出: 我叫张三,今年25岁,身高1.75米。
# f-string可以包含表达式
print(f"明年我将{age + 1}岁") # 输出: 明年我将26岁
print(f"我的平均分是{sum(scores.values()) / len(scores):.1f}") # 输出: 我的平均分是85.0
# 使用format()方法
formatted = "我叫{},今年{}岁,身高{:.2f}米。".format(name, age, height)
print(formatted) # 输出: 我叫张三,今年25岁,身高1.75米。
# 使用format()方法带有命名参数
formatted = "我叫{name},今年{age}岁,身高{height:.2f}米。".format(name=name, age=age, height=height)
print(formatted) # 输出: 我叫张三,今年25岁,身高1.75米。
# 使用format()方法带有位置索引
formatted = "我的成绩:语文{0}分,数学{1}分,英语{2}分".format(scores["语文"], scores["数学"], scores["英语"])
print(formatted) # 输出: 我的成绩:语文85分,数学92分,英语78分
# 使用%运算符(旧式格式化,类似C语言)
formatted = "我叫%s,今年%d岁,身高%.2f米。" % (name, age, height)
print(formatted) # 输出: 我叫张三,今年25岁,身高1.75米。
# 格式化表格数据
students = [
{"姓名": "张三", "年龄": 20, "成绩": 85},
{"姓名": "李四", "年龄": 22, "成绩": 92},
{"姓名": "王五", "年龄": 21, "成绩": 78}
]
# 打印表头
print(f"{'姓名':<10}{'年龄':<10}{'成绩':<10}")
print("-" * 30)
# 打印每行数据
for student in students:
print(f"{student['姓名']:<10}{student['年龄']:<10}{student['成绩']:<10}")
# 输出:
# 姓名 年龄 成绩
# ------------------------------
# 张三 20 85
# 李四 22 92
# 王五 21 78
# 字符串分割
text = "Python,Java,C++,JavaScript"
languages = text.split(",")
print(languages) # 输出: ['Python', 'Java', 'C++', 'JavaScript']
# 限制分割次数
languages = text.split(",", 2)
print(languages) # 输出: ['Python', 'Java', 'C++,JavaScript']
# 按行分割
text = """第一行
第二行
第三行"""
lines = text.splitlines()
print(lines) # 输出: ['第一行', '第二行', '第三行']
# 字符串连接
languages = ["Python", "Java", "C++", "JavaScript"]
text = ", ".join(languages)
print(text) # 输出: Python, Java, C++, JavaScript
# 实际应用:处理CSV数据
csv_line = "张三,25,北京,工程师"
name, age, city, occupation = csv_line.split(",")
print(f"姓名: {name}, 职业: {occupation}") # 输出: 姓名: 张三, 职业: 工程师
# 实际应用:构建URL查询参数
params = {"user": "admin", "action": "login", "redirect": "/dashboard"}
query_string = "&".join([f"{key}={value}" for key, value in params.items()])
url = f"https://example.com/api?{query_string}"
print(url) # 输出: https://example.com/api?user=admin&action=login&redirect=/dashboard
字符串本身是不可变的,但可以通过创建新字符串来实现修改:
# 移除空白
text = " Python编程 "
print(text.strip()) # 输出: "Python编程"
print(text.lstrip()) # 输出: "Python编程 "(只移除左侧空白)
print(text.rstrip()) # 输出: " Python编程"(只移除右侧空白)
# 移除特定字符
text = "###Python编程###"
print(text.strip("#")) # 输出: "Python编程"
# 大小写转换
text = "Python Programming"
print(text.upper()) # 输出: "PYTHON PROGRAMMING"
print(text.lower()) # 输出: "python programming"
print(text.title()) # 输出: "Python Programming"(每个单词首字母大写)
print(text.capitalize()) # 输出: "Python programming"(首字母大写)
print(text.swapcase()) # 输出: "pYTHON pROGRAMMING"(交换大小写)
# 实际应用:标准化用户数据
emails = ["[email protected]", "[email protected]", "[email protected]"]
standardized_emails = [email.lower() for email in emails]
print(standardized_emails) # 输出: ['[email protected]', '[email protected]', '[email protected]']
# 简单的文本分析
text = """
Python是一种广泛使用的解释型、高级编程语言,由吉多·范罗苏姆创建,第一版发布于1991年。
Python的设计具有很强的可读性,它使用大量的缩进和空白符号。
Python支持多种编程范式,包括面向对象、命令式、函数式和过程式编程。
"""
# 统计单词出现次数
words = text.replace("\n", "").replace(",", "").replace("。", "").replace("·", "").split()
word_count = {}
for word in words:
if word in word_count:
word_count[word] += 1
else:
word_count[word] = 1
# 显示出现次数最多的5个单词
sorted_words = sorted(word_count.items(), key=lambda x: x[1], reverse=True)
print("出现次数最多的单词:")
for word, count in sorted_words[:5]:
print(f"{word}: {count}次")
# 计算平均单词长度
total_length = sum(len(word) for word in words)
average_length = total_length / len(words) if words else 0
print(f"平均单词长度: {average_length:.1f}个字符")
为了巩固本章所学内容,下面提供了几个实用的编程练习及其解决方案。请先自行尝试解决,然后再查看参考答案。
题目:创建一个包含你最喜欢的书籍名称的列表,然后使用列表推导式创建一个新列表,只包含字符数大于5的书籍名称。
参考解答:
# 创建书籍列表
books = ["三体", "活着", "围城", "红楼梦", "百年孤独", "基督山伯爵", "平凡的世界"]
# 使用列表推导式筛选长度大于5的书名
long_titles = [book for book in books if len(book) > 5]
print(f"长标题书籍: {long_titles}") # 输出: 长标题书籍: ['百年孤独', '基督山伯爵', '平凡的世界']
# 按书名长度排序
sorted_by_length = sorted(books, key=len)
print(f"按长度排序: {sorted_by_length}") # 从短到长排序
# 按书名长度逆序排序
reverse_sorted = sorted(books, key=len, reverse=True)
print(f"按长度逆序: {reverse_sorted}") # 从长到短排序
题目:创建一个学生信息字典,包含姓名、年龄、成绩等信息,并编写代码根据成绩判断学生的等级(A、B、C、D、F)。
参考解答:
# 创建学生信息字典
student = {
"姓名": "张明",
"年龄": 20,
"成绩": {
"语文": 85,
"数学": 92,
"英语": 78,
"物理": 88,
"化学": 76
}
}
# 计算平均分
scores = student["成绩"]
average_score = sum(scores.values()) / len(scores)
print(f"{student['姓名']}的平均分为: {average_score:.1f}")
# 根据平均分确定等级
def get_grade(score):
if score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
elif score >= 60:
return "D"
else:
return "F"
grade = get_grade(average_score)
print(f"{student['姓名']}的等级为: {grade}")
# 查找最高分和最低分科目
max_subject = max(scores.items(), key=lambda x: x[1])
min_subject = min(scores.items(), key=lambda x: x[1])
print(f"最高分科目: {max_subject[0]}, 分数: {max_subject[1]}")
# 打印所有不及格科目(如果有)
failed_subjects = [subject for subject, score in scores.items() if score < 60]
if failed_subjects:
print(f"不及格科目: {', '.join(failed_subjects)}")
else:
print("没有不及格科目,继续保持!")
题目:创建两个集合:一个包含110的偶数,另一个包含110的奇数,然后计算它们的并集、交集和差集。
参考解答:
# 创建集合
even_numbers = {2, 4, 6, 8, 10}
odd_numbers = {1, 3, 5, 7, 9}
# 验证集合内容
print(f"偶数集合: {even_numbers}")
print(f"奇数集合: {odd_numbers}")
# 使用集合推导式创建(另一种方法)
even_set = {x for x in range(1, 11) if x % 2 == 0}
odd_set = {x for x in range(1, 11) if x % 2 == 1}
print(f"使用集合推导式 - 偶数: {even_set}")
print(f"使用集合推导式 - 奇数: {odd_set}")
# 计算并集
union_set = even_numbers | odd_numbers
print(f"并集: {union_set}") # 应该是1到10的所有数字
# 计算交集
intersection_set = even_numbers & odd_numbers
print(f"交集: {intersection_set}") # 应该是空集合
# 计算差集
difference_even_odd = even_numbers - odd_numbers
print(f"差集(偶数-奇数): {difference_even_odd}") # 应该等于偶数集合
difference_odd_even = odd_numbers - even_numbers
print(f"差集(奇数-偶数): {difference_odd_even}") # 应该等于奇数集合
# 对称差集
symmetric_difference = even_numbers ^ odd_numbers
print(f"对称差集: {symmetric_difference}") # 应该等于并集(因为没有共同元素)
# 验证性质
print(f"偶数集合是奇数集合的子集? {even_numbers.issubset(odd_numbers)}") # False
print(f"全集是偶数集合的超集? {union_set.issuperset(even_numbers)}") # True
题目:编写一个程序,统计一个字符串中每个字符出现的次数,并以字典形式返回结果。
参考解答:
def count_characters(text):
"""统计字符串中每个字符出现的次数"""
char_count = {}
for char in text:
if char in char_count:
char_count[char] += 1
else:
char_count[char] = 1
return char_count
# 测试函数
sample_text = "Python编程很有趣,Python是一门优雅的语言!"
result = count_characters(sample_text)
# 打印结果
print("字符统计结果:")
for char, count in result.items():
print(f"'{char}': {count}次")
# 找出出现次数最多的字符
most_common = max(result.items(), key=lambda x: x[1])
print(f"\n出现最多的字符是 '{most_common[0]}',共出现了 {most_common[1]} 次")
# 使用collections.Counter(更简洁的方法)
from collections import Counter
counter = Counter(sample_text)
print("\n使用Counter的结果:")
most_common_chars = counter.most_common(3) # 获取出现最多的3个字符
for char, count in most_common_chars:
print(f"'{char}': {count}次")
题目:创建一个购物清单程序,使用列表或字典来存储商品和价格,并实现添加商品、删除商品、显示所有商品和计算总价等功能。
参考解答:
class ShoppingList:
def __init__(self):
self.items = {} # 使用字典存储商品名称和价格
def add_item(self, name, price, quantity=1):
"""添加商品到购物清单"""
if name in self.items:
# 如果商品已存在,更新数量和总价
self.items[name]['quantity'] += quantity
self.items[name]['total'] = self.items[name]['price'] * self.items[name]['quantity']
else:
# 添加新商品
self.items[name] = {
'price': price,
'quantity': quantity,
'total': price * quantity
}
print(f"已添加: {name} x{quantity}, 单价: ¥{price}")
def remove_item(self, name, quantity=None):
"""从购物清单中移除商品"""
if name not in self.items:
print(f"购物清单中没有 {name}")
return
if quantity is None or quantity >= self.items[name]['quantity']:
# 移除所有该商品
del self.items[name]
print(f"已移除所有 {name}")
else:
# 减少商品数量
self.items[name]['quantity'] -= quantity
self.items[name]['total'] = self.items[name]['price'] * self.items[name]['quantity']
print(f"已移除: {name} x{quantity}")
def display_list(self):
"""显示购物清单"""
if not self.items:
print("购物清单为空")
return
print("\n当前购物清单:")
print("-" * 45)
print(f"{'商品名称':<15}{'单价':>8}{'数量':>8}{'合计':>12}")
print("-" * 45)
for name, details in self.items.items():
print(f"{name:<15}¥{details['price']:>7.2f}{details['quantity']:>8}¥{details['total']:>11.2f}")
print("-" * 45)
total = sum(item['total'] for item in self.items.values())
print(f"{'总计':>32}¥{total:>11.2f}")
def calculate_total(self):
"""计算购物清单总价"""
return sum(item['total'] for item in self.items.values())
# 测试购物清单程序
shopping = ShoppingList()
# 添加商品
shopping.add_item("苹果", 5.5, 3)
shopping.add_item("牛奶", 6.8, 2)
shopping.add_item("面包", 12.5)
shopping.display_list()
# 更新商品数量
shopping.add_item("苹果", 5.5, 2) # 再添加2个苹果
shopping.display_list()
# 移除商品
shopping.remove_item("牛奶", 1) # 移除1份牛奶
shopping.display_list()
# 计算总价
total = shopping.calculate_total()
print(f"购物总价: ¥{total:.2f}")
通过完成这些练习,你将能够更好地理解和应用Python的数据结构。尝试修改这些代码来适应不同的需求,或者创建自己的练习题目来加深理解。
在本章中,我们学习了Python的主要数据结构:
这些数据结构是Python编程的基础,掌握它们将使你能够更有效地组织和处理数据。在下一章中,我们将学习Python的函数,进一步提高代码的模块化和重用性。