当前位置:首页>python>Python元组与集合:不可变序列与无序集合

Python元组与集合:不可变序列与无序集合

  • 2026-09-08 12:50:29
Python元组与集合:不可变序列与无序集合

元组是"只读列表",集合是"不重复的数学集合",用对场景让代码更高效

🎯 本章目标学完本章,你会:

  1. ✅ 理解元组的特点和应用场景

  2. ✅ 掌握元组的基本操作和方法

  3. ✅ 理解集合的特点和数学运算

  4. ✅ 掌握集合的基本操作和集合运算

  5. ✅ 能在测试中选择合适的数据结构


🔐 元组(Tuple):不可变的序列

什么是元组?

元组是一种有序、不可变的数据结构。一旦创建,就不能修改、添加或删除元素。

现实比喻:

  • 元组 = 身份证信息(姓名、身份证号、出生日期,不能改)

  • 列表 = 购物清单(可以随时修改)

为什么需要元组?

  1. 数据安全:防止数据被意外修改

  2. 性能更好:比列表处理速度快

  3. 可作为字典键:因为不可变,所以可哈希

  4. 函数多返回值:函数返回多个值时,实际上是返回一个元组


创建元组

# 空元组empty_tuple = ()empty_tuple2 = tuple()# 一个元素的元组(注意必须有逗号!)single1 = (1,)      # 正确:(1,)single2 = 1,        # 正确:(1,)# single3 = (1)     # 错误:这只是一个数字1,不是元组# 多个元素的元组fruits = ("苹果", "香蕉", "橙子")numbers = (1, 2, 3, 4, 5)# 不用括号也可以(元组打包)person = "张三", 25, "北京"  # ("张三", 25, "北京")# 从列表创建list_data = [1, 2, 3]tuple_from_list = tuple(list_data)  # (1, 2, 3)# 混合类型mixed = ("文本", 123, 3.14, True, None)# 测试中的元组test_case = ("TC001", "登录测试", "高", 5.2)status_codes = (200, 301, 400, 404, 500)

访问元组元素

# 索引访问(和列表一样)fruits = ("苹果", "香蕉", "橙子", "葡萄", "芒果")print(fruits[0])   # 苹果print(fruits[-1])  # 芒果print(fruits[2])   # 橙子# 切片操作print(fruits[1:4])    # ("香蕉", "橙子", "葡萄")print(fruits[:3])     # ("苹果", "香蕉", "橙子")print(fruits[::2])    # ("苹果", "橙子", "芒果")print(fruits[::-1])   # ("芒果", "葡萄", "橙子", "香蕉", "苹果")# 解包(Unpacking)person = ("张三", 25, "北京")name, age, city = personprint(name)  # 张三print(age)   # 25print(city)  # 北京# 星号解包numbers = (1, 2, 3, 4, 5, 6, 7)first, *middle, last = numbersprint(first)   # 1print(middle)  # [2, 3, 4, 5, 6]  # 注意:星号得到的是列表print(last)    # 7# 实战:处理测试结果test_result = ("TC001", "登录测试", "passed", 2.5)test_id, test_name, status, duration = test_resultprint(f"测试{test_id}结果: {status}, 耗时{duration}秒")

元组的不可变性

# 元组创建后不能修改fruits = ("苹果", "香蕉", "橙子")# 以下操作都会报错!# fruits[0] = "芒果"       # TypeError: 'tuple' object does not support item assignment# fruits.append("葡萄")    # AttributeError: 'tuple' object has no attribute 'append'# fruits.remove("苹果")    # AttributeError: 'tuple' object has no attribute 'remove'# del fruits[0]           # TypeError: 'tuple' object doesn't support item deletion# 但是!如果元组包含可变对象,可以修改可变对象内部nested_tuple = (1, 2, [3, 4])nested_tuple[2].append(5)  # 可以!修改列表内部print(nested_tuple)  # (1, 2, [3, 4, 5])# 元组可以重新赋值fruits = ("苹果", "香蕉", "橙子")fruits = ("芒果", "西瓜")  # 可以,创建新元组

元组的常用操作

fruits = ("苹果", "香蕉", "橙子", "葡萄", "香蕉")# 长度length = len(fruits)  # 5# 计数count = fruits.count("香蕉")  # 2count2 = fruits.count("苹果")  # 1count3 = fruits.count("西瓜")  # 0# 查找索引index = fruits.index("橙子")  # 2index2 = fruits.index("香蕉")  # 1(返回第一个)index3 = fruits.index("香蕉", 2)  # 4(从索引2开始找)# 检查元素是否存在has_apple = "苹果" in fruits  # Truehas_mango = "芒果" in fruits  # Falsenot_has_mango = "芒果" not in fruits  # True# 最大值/最小值(同类型可比较)numbers = (5, 2, 8, 1, 9)max_num = max(numbers)  # 9min_num = min(numbers)  # 1# 求和total = sum(numbers)  # 25# 排序(返回列表)sorted_numbers = sorted(numbers)  # [1, 2, 5, 8, 9]sorted_desc = sorted(numbers, reverse=True)  # [9, 8, 5, 2, 1]# 连接元组tuple1 = (1, 2, 3)tuple2 = (4, 5, 6)combined = tuple1 + tuple2  # (1, 2, 3, 4, 5, 6)# 重复元组repeated = tuple1 * 3  # (1, 2, 3, 1, 2, 3, 1, 2, 3)

元组 vs 列表

特性

元组

列表

可变性

❌ 不可变

✅ 可变

性能

⚡ 更快

🐢 较慢

内存占用

💾 较小

💾 较大

安全性

🔒 高(数据安全)

⚠️ 低

功能

📦 较少

🧰 丰富

使用场景

常量、配置、函数返回值

动态数据集合

可哈希性

✅ 可哈希(可作为字典键)

❌ 不可哈希

元组在测试中的应用

# 1. 存储常量配置HTTP_METHODS = ("GET", "POST", "PUT", "DELETE", "PATCH")TEST_ENVIRONMENTS = ("development", "staging", "production")PRIORITY_LEVELS = ("blocker", "critical", "major", "minor", "trivial")# 2. 函数返回多个值def run_test(test_name):    """执行测试并返回结果"""    # 模拟测试执行    import random    status = random.choice(["passed", "failed", "error"])    duration = random.uniform(0.5, 5.0)    error_message = "" if status == "passed" else "测试失败"    return test_name, status, duration, error_message  # 返回元组# 接收多个返回值test_name, status, duration, error = run_test("登录测试")print(f"测试: {test_name}")print(f"状态: {status}")print(f"耗时: {duration:.2f}秒")if error:    print(f"错误: {error}")# 3. 作为字典的键(因为元组不可变)test_coverage = {    ("登录模块", "V1.0"): 85,    ("支付模块", "V1.0"): 90,    ("用户模块", "V1.1"): 78}print(f"登录模块覆盖率: {test_coverage[('登录模块', 'V1.0')]}%")# 4. 命名元组(更高级的用法)from collections import namedtuple# 定义测试用例的结构TestCase = namedtuple("TestCase", ["id", "name", "priority", "duration"])# 创建测试用例实例tc1 = TestCase("TC001", "登录测试", "高", 5.2)tc2 = TestCase("TC002", "注册测试", "中", 3.8)# 访问(像属性一样)print(f"{tc1.id}: {tc1.name}, 优先级: {tc1.priority}")# 也可以通过索引访问print(f"耗时: {tc1[3]}秒")

🎲 集合(Set):无序的唯一集合

什么是集合?

集合是一种无序、不重复的数据结构。集合中的元素必须是可哈希的(不可变类型)。

现实比喻:

  • 集合 = 数学中的集合,或者一个没有重复元素的袋子

  • 列表 = 有序队列,可以有重复

  • 元组 = 固定队列,不能修改

为什么需要集合?

  1. 去重:自动去除重复元素

  2. 集合运算:交集、并集、差集等

  3. 快速成员检查:比列表、元组快得多

  4. 数学建模:适合需要集合运算的场景


创建集合

# 空集合(注意:不能用{},{}是空字典)empty_set = set()# 创建集合fruits = {"苹果", "香蕉", "橙子"}numbers = {1, 2, 3, 4, 5}# 从列表创建(去重)duplicate_list = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]unique_set = set(duplicate_list)  # {1, 2, 3, 4}# 从字符串创建chars = set("hello")  # {'h', 'e', 'l', 'o'}  # 注意:只有一个'l'# 从元组创建tuple_data = (1, 2, 2, 3, 3, 3)set_from_tuple = set(tuple_data)  # {1, 2, 3}# 集合推导式squares = {x**2 for x in range(5)}  # {0, 1, 4, 9, 16}even_squares = {x**2 for x in range(10) if x % 2 == 0} # {0, 4, 16, 36, 64}

集合的基本操作

# 添加元素fruits = {"苹果", "香蕉", "橙子"}fruits.add("葡萄")      # 添加单个元素fruits.update(["芒果", "西瓜"])  # 添加多个元素fruits.update({"菠萝", "桃子"})  # 添加另一个集合的元素# 移除元素fruits = {"苹果", "香蕉", "橙子", "葡萄", "芒果"}fruits.remove("香蕉")    # 移除元素,如果元素不存在会报错fruits.discard("西瓜")   # 移除元素,如果元素不存在不会报错removed = fruits.pop()   # 随机移除一个元素并返回fruits.clear()          # 清空集合# 实战:管理测试用例test_cases = {"登录测试", "注册测试", "支付测试"}test_cases.add("搜索测试")           # 添加新测试用例test_cases.update(["购物车测试", "订单测试"])  # 添加多个test_cases.discard("已废弃的测试")  # 安全移除,不存在也不会报错# 检查元素是否存在fruits = {"苹果", "香蕉", "橙子"}has_apple = "苹果" in fruits     # Truehas_mango = "芒果" not in fruits  # True# 遍历集合for fruit in fruits:    print(fruit)

集合运算

# 定义两个集合A = {1, 2, 3, 4, 5}B = {4, 5, 6, 7, 8}# 并集(A ∪ B)union = A | B               # {1, 2, 3, 4, 5, 6, 7, 8}union2 = A.union(B)         # 同上# 交集(A ∩ B)intersection = A & B        # {4, 5}intersection2 = A.intersection(B)  # 同上# 差集(A - B)difference = A - B          # {1, 2, 3}difference2 = A.difference(B)  # 同上# 对称差集(A △ B)symmetric_diff = A ^ B      # {1, 2, 3, 6, 7, 8}symmetric_diff2 = A.symmetric_difference(B)  # 同上# 子集和超集C = {2, 3}is_subset = C <= A          # True,C是A的子集is_superset = A >= C        # True,A是C的超集is_proper_subset = C < A    # True,C是A的真子集is_proper_superset = A > C  # True,A是C的真超集# 实战:测试用例分析all_test_cases = {"T1", "T2", "T3", "T4", "T5", "T6"}executed_test_cases = {"T1", "T3", "T5"}passed_test_cases = {"T1", "T3"}# 未执行的测试用例not_executed = all_test_cases - executed_test_cases  # {"T2", "T4", "T6"}# 执行但未通过的测试用例executed_but_failed = executed_test_cases - passed_test_cases  # {"T5"}# 通过的测试用例占比if all_test_cases:    pass_rate = len(passed_test_cases) / len(all_test_cases) * 100else:    pass_rate = 0print(f"测试通过率: {pass_rate:.1f}%")

集合的常用方法

# 创建两个集合A = {1, 2, 3, 4, 5}B = {4, 5, 6, 7, 8}# 长度length = len(A)  # 5# 复制C = A.copy()  # {1, 2, 3, 4, 5}# 判断是否不相交is_disjoint = A.isdisjoint({6, 7, 8})  # True,没有共同元素is_disjoint2 = A.isdisjoint({4, 5, 6})  # False,有共同元素# 更新方法(原地修改)A = {1, 2, 3, 4, 5}B = {4, 5, 6, 7, 8}A.update(B)  # A变成{1, 2, 3, 4, 5, 6, 7, 8}A = {1, 2, 3, 4, 5}A.intersection_update(B)  # A变成{4, 5}A = {1, 2, 3, 4, 5}A.difference_update(B)  # A变成{1, 2, 3}A = {1, 2, 3, 4, 5}A.symmetric_difference_update(B)  # A变成{1, 2, 3, 6, 7, 8}

集合在测试中的应用

# 1. 测试用例去重test_cases = ["登录测试", "注册测试", "登录测试", "支付测试", "注册测试"]unique_test_cases = set(test_cases)  # {'登录测试', '注册测试', '支付测试'}print(f"去重后测试用例数: {len(unique_test_cases)}")# 2. 检查测试覆盖required_features = {"登录", "注册", "支付", "搜索", "购物车", "订单"}tested_features = {"登录", "注册", "支付"}# 已覆盖的功能covered = required_features & tested_featuresprint(f"已覆盖功能: {covered}")# 未覆盖的功能not_covered = required_features - tested_featuresprint(f"未覆盖功能: {not_covered}")# 覆盖率if required_features:    coverage_rate = len(covered) / len(required_features) * 100else:    coverage_rate = 0print(f"功能覆盖率: {coverage_rate:.1f}%")# 3. 查找重复的Bug报告bug_reports = [    "Bug001: 登录失败",    "Bug002: 支付超时",     "Bug003: 页面卡顿",    "Bug004: 登录失败",  # 重复    "Bug005: 支付超时"   # 重复]# 查找重复的Bugseen = set()duplicates = set()for bug in bug_reports:    if bug in seen:        duplicates.add(bug)    else:        seen.add(bug)print(f"重复的Bug报告: {duplicates}")# 4. 权限检查user_roles = {"admin", "editor", "viewer"}required_roles = {"admin", "editor"}# 检查用户是否有足够权限if user_roles & required_roles:    print("用户有部分权限")else:    print("用户无权限")# 检查用户是否具有所有所需权限if required_roles <= user_roles:  # 子集判断    print("用户具有所有所需权限")else:    missing = required_roles - user_roles    print(f"缺少权限: {missing}")

集合 vs 列表 vs 元组

特性

列表

元组

集合

有序性

✅ 有序

✅ 有序

❌ 无序

可变性

✅ 可变

❌ 不可变

✅ 可变

重复元素

✅ 允许

✅ 允许

❌ 不允许

索引访问

✅ 支持

✅ 支持

❌ 不支持

查找速度

🐢 慢

🐢 慢

⚡ 快

内存占用

💾 较大

💾 较小

💾 较大

主要用途

动态数据集合

固定数据集合

唯一元素、集合运算


📊 四种数据结构总结对比

数据结构

可变性

有序性

重复元素

使用场景

列表

✅ 可变

✅ 有序

✅ 允许

动态数据集合,需要增删改查

元组

❌ 不可变

✅ 有序

✅ 允许

常量、配置、函数返回值、字典键

集合

✅ 可变

❌ 无序

❌ 不允许

去重、集合运算、快速成员检查

字典

✅ 可变

✅ 有序(3.7+)

✅ 键唯一

键值对映射、结构化数据


📋 本章检查清单

  • [ ] 理解元组是不可变的、有序的序列

  • [ ] 掌握元组的创建、访问和解包

  • [ ] 理解元组的不可变性及其应用场景

  • [ ] 理解集合是无序的、不重复的集合

  • [ ] 掌握集合的创建、添加、删除操作

  • [ ] 掌握集合运算(并集、交集、差集、对称差集)

  • [ ] 能在测试中灵活使用元组和集合

  • [ ] 理解列表、元组、集合、字典的区别和适用场景


🎉 恭喜!元组和集合掌握完成

现在你已经学会了Python中四种重要的数据结构:

  1. 列表:有序、可变、可重复

  2. 字典:键值对、无序、键唯一

  3. 元组:有序、不可变、可重复

  4. 集合:无序、不重复、集合运算

关键收获:

  1. ✅ 元组:用于不可变数据,如配置、函数返回值

  2. ✅ 集合:用于去重和集合运算

  3. ✅ 选择合适的数据结构:根据需求选择最合适的结构

下一章预告:序列-基本的数据结构序列

准备好了吗?让我们继续前进!🚀

记住:不同的数据结构适用于不同的场景。在写代码时,多思考一下:"这个数据用什么结构存储最合适?"

最新文章

随机文章