字典就像现实世界的字典一样,通过"键"快速找到对应的"值"
🎯 本章目标学完本章,你会:
✅ 理解字典的概念和特点
✅ 掌握字典的创建、访问、修改操作
✅ 熟练使用字典的各种方法
✅ 理解字典的嵌套结构
✅ 能在测试中灵活使用字典存储结构化数据
🎪 开篇:为什么需要字典?
想象一下这个场景:你需要管理测试用户的数据
没有字典的世界:
# 用多个变量存储用户信息username = "张三"age = 25email = "zhangsan@example.com"phone = "13800138000"city = "北京"# 要传递用户信息?得传5个参数!def process_user(username, age, email, phone, city): ...# 要添加新字段?得改所有相关函数!
有字典的世界:
# 用一个字典存储所有用户信息user = { "username": "张三", "age": 25, "email": "zhangsan@example.com", "phone": "13800138000", "city": "北京"}# 传递用户信息?只需要传1个字典!def process_user(user_data): name = user_data["username"] age = user_data["age"] ...# 要添加新字段?直接加到字典里!user["gender"] = "男"
字典让相关数据的组织变得简单!
📦 什么是字典?
直观理解
字典就像一本电话簿:
姓名 = 键(key)
电话号码 = 值(value)
通过姓名快速找到电话
每个人的电话可以不同
技术定义
字典是Python中的一种键值对集合:
无序:Python 3.7+版本会保持插入顺序
可变:可以修改、添加、删除键值对
键唯一:键不能重复
键不可变:键必须是不可变类型(字符串、数字、元组)
值任意:值可以是任意类型
五个关键特性:
键值对:每个元素由键和值组成
快速查找:通过键快速找到值
键必须唯一:重复的键会覆盖
键必须不可变:不能使用列表、字典等可变类型作为键
值可以任意:可以存储任何类型的数据
🆕 创建字典:四种方法
方法1:花括号直接创建(最常用)
# 空字典empty_dict = {}empty_dict2 = dict()# 创建字典person = { "name": "张三", "age": 25, "city": "北京"}# 测试用例字典test_case = { "id": "TC001", "name": "登录功能测试", "priority": "高", "expected_result": "登录成功", "actual_result": "登录成功"}# 接口请求数据api_request = { "url": "/api/login", "method": "POST", "headers": {"Content-Type": "application/json"}, "body": {"username": "test", "password": "123456"}}
方法2:dict()函数创建
# 从键值对列表创建person = dict([("name", "张三"), ("age", 25), ("city", "北京")])# 从关键字参数创建person = dict(name="张三", age=25, city="北京")# 实战:创建测试配置test_config = dict( base_url="https://test.example.com", timeout=30, retry_times=3, browser="chrome")
方法3:字典推导式
# 创建数字平方的字典squares = {x: x**2 for x in range(1, 6)}# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}# 从列表创建字典keys = ["name", "age", "city"]values = ["张三", 25, "北京"]person = {k: v for k, v in zip(keys, values)}# {'name': '张三', 'age': 25, 'city': '北京'}# 实战:创建测试数据映射test_cases = ["登录测试", "注册测试", "支付测试"]statuses = ["passed", "failed", "passed"]test_results = {case: status for case, status in zip(test_cases, statuses)}# {'登录测试': 'passed', '注册测试': 'failed', '支付测试': 'passed'}
方法4:fromkeys()方法
# 创建具有相同默认值的字典keys = ["name", "age", "city"]default_dict = dict.fromkeys(keys, "未知")# {'name': '未知', 'age': '未知', 'city': '未知'}# 实战:初始化测试结果test_case_ids = ["TC001", "TC002", "TC003", "TC004"]test_results = dict.fromkeys(test_case_ids, "pending")# {'TC001': 'pending', 'TC002': 'pending', 'TC003': 'pending', 'TC004': 'pending'}
🔍 访问字典元素
通过键访问
person = { "name": "张三", "age": 25, "city": "北京"}# 直接通过键访问name = person["name"] # "张三"age = person["age"] # 25# 访问不存在的键会报错# phone = person["phone"] # KeyError: 'phone'# 实战:获取测试信息test_case = { "id": "TC001", "name": "登录测试", "priority": "高", "duration": 5.2}test_id = test_case["id"] # "TC001"test_name = test_case["name"] # "登录测试"test_duration = test_case["duration"] # 5.2
使用get()方法(推荐)
person = { "name": "张三", "age": 25}# 使用get()方法访问name = person.get("name") # "张三"phone = person.get("phone") # None(不报错)# 设置默认值phone = person.get("phone", "未知") # "未知"city = person.get("city", "北京") # "北京"# 实战:安全获取测试配置test_config = { "base_url": "https://test.example.com", "timeout": 30}# 安全的获取方式browser = test_config.get("browser", "chrome") # "chrome"retry = test_config.get("retry_times", 3) # 3timeout = test_config.get("timeout", 10) # 30
检查键是否存在
person = {"name": "张三", "age": 25}# 使用in检查键是否存在has_name = "name" in person # Truehas_phone = "phone" in person # Falsehas_not_phone = "phone" not in person # True# 使用keys()方法获取所有键keys = person.keys() # dict_keys(['name', 'age'])# 实战:检查测试字段test_case = { "id": "TC001", "name": "登录测试", "priority": "高"}# 检查必要字段required_fields = ["id", "name", "priority", "expected"]for field in required_fields: if field not in test_case: print(f"⚠️ 缺少必要字段: {field}")
获取所有键、值、键值对
person = { "name": "张三", "age": 25, "city": "北京"}# 获取所有键keys = person.keys() # dict_keys(['name', 'age', 'city'])keys_list = list(keys) # ['name', 'age', 'city']# 获取所有值values = person.values() # dict_values(['张三', 25, '北京'])values_list = list(values) # ['张三', 25, '北京']# 获取所有键值对items = person.items() # dict_items([('name', '张三'), ('age', 25), ('city', '北京')])items_list = list(items) # [('name', '张三'), ('age', 25), ('city', '北京')]# 实战:分析测试结果test_results = { "登录测试": "passed", "注册测试": "failed", "支付测试": "passed", "搜索测试": "passed"}# 获取所有测试名称test_names = list(test_results.keys())# ['登录测试', '注册测试', '支付测试', '搜索测试']# 获取所有测试结果results = list(test_results.values())# ['passed', 'failed', 'passed', 'passed']# 统计通过数passed_count = results.count("passed") # 3total = len(results) # 4pass_rate = passed_count / total * 100print(f"通过率: {pass_rate:.1f}%") # 75.0%
✏️ 修改字典元素
修改现有值
person = { "name": "张三", "age": 25, "city": "北京"}# 直接修改person["age"] = 26person["city"] = "上海"# 批量修改person.update({"age": 27, "city": "广州"})# 实战:更新测试状态test_result = { "status": "running", "progress": 0, "start_time": "2024-01-15 10:00:00"}# 更新测试状态test_result["status"] = "completed"test_result["progress"] = 100test_result["end_time"] = "2024-01-15 10:05:30"test_result["duration"] = 5.5
添加新键值对
person = {"name": "张三", "age": 25}# 直接添加person["city"] = "北京"person["phone"] = "13800138000"# 使用update()批量添加person.update({"email": "zhangsan@example.com", "gender": "男"})# 使用setdefault()添加(如果键不存在)person.setdefault("country", "中国")# 实战:添加测试信息test_case = { "id": "TC001", "name": "登录测试"}# 添加更多信息test_case["priority"] = "高"test_case["author"] = "张三"test_case["create_date"] = "2024-01-15"# 添加测试步骤test_case["steps"] = [ "打开登录页面", "输入用户名", "输入密码", "点击登录按钮"]
❌ 删除字典元素
del语句
person = { "name": "张三", "age": 25, "city": "北京", "phone": "13800138000"}# 删除指定键del person["phone"] # 删除phone键# 结果:{'name': '张三', 'age': 25, 'city': '北京'}# 删除整个字典# del person # 字典被删除,不能再访问# 实战:清理测试数据test_data = { "user_id": 123, "username": "test", "password": "secret", "token": "abc123", "session_id": "xyz789"}# 删除敏感信息del test_data["password"]del test_data["token"]del test_data["session_id"]# 结果:{'user_id': 123, 'username': 'test'}
pop()方法
person = { "name": "张三", "age": 25, "city": "北京"}# 删除指定键并返回值age = person.pop("age") # 返回25,person变成{'name': '张三', 'city': '北京'}# 指定默认值(键不存在时返回默认值)phone = person.pop("phone", "未知") # 返回"未知",person不变# 实战:处理测试结果test_results = { "登录测试": "passed", "注册测试": "failed", "支付测试": "pending"}# 取出并处理完成的测试completed_test = test_results.pop("登录测试")print(f"处理完成的测试: 登录测试 - {completed_test}")# test_results变成{'注册测试': 'failed', '支付测试': 'pending'}
popitem()方法
person = { "name": "张三", "age": 25, "city": "北京"}# 删除最后一个键值对(Python 3.7+)key, value = person.popitem() # 返回('city', '北京')# person变成{'name': '张三', 'age': 25}# 实战:后进先出处理测试队列test_queue = { "TC001": "pending", "TC002": "pending", "TC003": "pending"}# 处理最后一个添加的测试test_id, status = test_queue.popitem()print(f"处理测试: {test_id}") # TC003
clear()方法
person = { "name": "张三", "age": 25, "city": "北京"}# 清空所有键值对person.clear() # {}# 实战:重置测试环境test_session = { "current_user": "张三", "token": "abc123", "permissions": ["read", "write"], "settings": {"theme": "dark"}}test_session.clear() # 清空会话数据print(f"会话已重置: {test_session}") # {}
🔄 遍历字典
遍历键
person = { "name": "张三", "age": 25, "city": "北京"}# 遍历键for key in person: print(f"键: {key}")# 使用keys()方法for key in person.keys(): print(f"键: {key}")# 实战:遍历测试配置test_config = { "base_url": "https://test.example.com", "timeout": 30, "retry_times": 3, "browser": "chrome"}print("测试配置检查:")for key in test_config: print(f" - {key}")
遍历值
person = { "name": "张三", "age": 25, "city": "北京"}# 遍历值for value in person.values(): print(f"值: {value}")# 实战:遍历测试结果test_results = { "登录测试": "passed", "注册测试": "failed", "支付测试": "passed"}print("测试结果:")for result in test_results.values(): status = "✅" if result == "passed" else "❌" print(f" {status}{result}")
遍历键值对
person = { "name": "张三", "age": 25, "city": "北京"}# 遍历键值对for key, value in person.items(): print(f"{key}: {value}")# 实战:生成测试报告test_results = { "登录测试": "passed", "注册测试": "failed", "支付测试": "passed", "搜索测试": "passed"}print("测试报告:")for test_name, result in test_results.items(): status = "✅" if result == "passed" else "❌" print(f"{status}{test_name}: {result}")
带索引的遍历
person = { "name": "张三", "age": 25, "city": "北京"}# 使用enumerate()获取索引for i, (key, value) in enumerate(person.items(), 1): print(f"{i}. {key}: {value}")# 实战:编号测试用例test_cases = { "TC001": "登录测试", "TC002": "注册测试", "TC003": "支付测试"}print("测试用例列表:")for i, (test_id, test_name) in enumerate(test_cases.items(), 1): print(f"{i}. {test_id}: {test_name}")
🎯 字典的常用方法
setdefault():安全设置默认值
# 基本用法person = {"name": "张三", "age": 25}# 如果键不存在,设置默认值city = person.setdefault("city", "北京") # 返回"北京",并设置city="北京"# 如果键存在,返回现有值age = person.setdefault("age", 30) # 返回25,不修改# 实战:初始化测试计数器test_counters = {}# 统计不同状态的测试数量test_results = ["passed", "failed", "passed", "passed", "failed", "error"]for result in test_results: # 如果结果类型不存在,初始化为0,然后加1 test_counters.setdefault(result, 0) test_counters[result] += 1print(test_counters) # {'passed': 3, 'failed': 2, 'error': 1}
update():批量更新
person = {"name": "张三", "age": 25}# 用另一个字典更新person.update({"age": 26, "city": "北京"})# 结果:{'name': '张三', 'age': 26, 'city': '北京'}# 用键值对列表更新person.update([("gender", "男"), ("phone", "13800138000")])# 用关键字参数更新person.update(email="zhangsan@example.com", country="中国")# 实战:合并测试配置base_config = { "base_url": "https://example.com", "timeout": 30}env_config = { "base_url": "https://test.example.com", "retry_times": 3}# 合并配置,后面的会覆盖前面的base_config.update(env_config)# 结果:{'base_url': 'https://test.example.com', 'timeout': 30, 'retry_times': 3}
copy():复制字典
# 浅拷贝original = {"name": "张三", "scores": [85, 90, 88]}copied = original.copy()# 修改原始字典original["name"] = "李四"original["scores"].append(95)print(original) # {'name': '李四', 'scores': [85, 90, 88, 95]}print(copied) # {'name': '张三', 'scores': [85, 90, 88, 95]}# 注意:列表是共享的,修改会影响两个字典# 实战:创建测试模板test_template = { "status": "pending", "start_time": None, "end_time": None, "duration": 0}# 创建多个测试实例test1 = test_template.copy()test2 = test_template.copy()test3 = test_template.copy()test1["status"] = "running"test2["status"] = "pending"test3["status"] = "completed"print(f"测试1: {test1}")print(f"测试2: {test2}")print(f"测试3: {test3}")
字典推导式
# 基本推导式squares = {x: x**2 for x in range(1, 6)}# {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}# 带条件的推导式even_squares = {x: x**2 for x in range(1, 11) if x % 2 == 0}# {2: 4, 4: 16, 6: 36, 8: 64, 10: 100}# 键值转换person = {"name": "张三", "age": 25}upper_case = {k.upper(): v for k, v in person.items()}# {'NAME': '张三', 'AGE': 25}# 实战:转换测试结果格式test_results = { "登录测试": "passed", "注册测试": "failed", "支付测试": "passed"}# 转换状态为图标formatted_results = { test: "✅ 通过" if status == "passed" else "❌ 失败" for test, status in test_results.items()}# {'登录测试': '✅ 通过', '注册测试': '❌ 失败', '支付测试': '✅ 通过'}# 筛选通过的测试passed_tests = { test: status for test, status in test_results.items() if status == "passed"}# {'登录测试': 'passed', '支付测试': 'passed'}
🎪 嵌套字典
字典中嵌套字典
# 嵌套字典company = { "employee1": { "name": "张三", "age": 25, "position": "工程师" }, "employee2": { "name": "李四", "age": 30, "position": "经理" }, "employee3": { "name": "王五", "age": 28, "position": "设计师" }}# 访问嵌套字典employee1_name = company["employee1"]["name"] # "张三"employee2_position = company["employee2"]["position"] # "经理"# 实战:测试用例管理test_suite = { "login": { "id": "TC001", "name": "登录功能测试", "priority": "高", "steps": ["输入用户名", "输入密码", "点击登录"], "expected": "登录成功" }, "register": { "id": "TC002", "name": "注册功能测试", "priority": "中", "steps": ["填写信息", "提交表单", "验证邮箱"], "expected": "注册成功" }, "payment": { "id": "TC003", "name": "支付功能测试", "priority": "高", "steps": ["选择商品", "填写支付信息", "确认支付"], "expected": "支付成功" }}# 获取登录测试的步骤login_steps = test_suite["login"]["steps"]login_priority = test_suite["login"]["priority"]
字典中嵌套列表
# 字典中嵌套列表student = { "name": "张三", "age": 20, "courses": ["数学", "物理", "化学", "英语"], "scores": [85, 90, 88, 92]}# 访问嵌套列表first_course = student["courses"][0] # "数学"average_score = sum(student["scores"]) / len(student["scores"]) # 88.75# 实战:测试执行记录test_execution = { "test_id": "TC001", "test_name": "登录测试", "status": "passed", "durations": [1.2, 1.5, 1.3, 1.4, 1.6], "errors": [], "screenshots": [ "screenshot_1.png", "screenshot_2.png", "screenshot_3.png" ]}# 计算平均执行时间avg_duration = sum(test_execution["durations"]) / len(test_execution["durations"])print(f"平均执行时间: {avg_duration:.2f}秒")# 检查是否有错误has_errors = len(test_execution["errors"]) > 0print(f"是否有错误: {has_errors}")
多层嵌套
# 多层嵌套数据结构test_environment = { "dev": { "database": { "host": "localhost", "port": 3306, "name": "test_db" }, "api": { "base_url": "https://dev.example.com", "timeout": 30 }, "users": [ {"username": "dev_user1", "role": "admin"}, {"username": "dev_user2", "role": "tester"} ] }, "staging": { "database": { "host": "staging.db.example.com", "port": 3306, "name": "staging_db" }, "api": { "base_url": "https://staging.example.com", "timeout": 60 }, "users": [ {"username": "stage_user1", "role": "admin"}, {"username": "stage_user2", "role": "tester"}, {"username": "stage_user3", "role": "viewer"} ] }}# 访问多层嵌套数据dev_db_host = test_environment["dev"]["database"]["host"] # "localhost"staging_timeout = test_environment["staging"]["api"]["timeout"] # 60first_staging_user = test_environment["staging"]["users"][0]["username"] # "stage_user1"
🧩 总结:字典的常用操作
操作 | 方法/语法 | 示例 | 结果 |
|---|
创建 | {}或 dict()
| {"a": 1, "b": 2}
| {"a": 1, "b": 2}
|
访问 | dict[key]或 dict.get(key)
| dict["a"]
| 1 |
添加/修改 | dict[key] = value
| dict["c"] = 3
| 添加键值对 |
删除 | del, pop(), popitem(), clear()
| dict.pop("a")
| 删除键"a" |
检查键 | key in dict
| "a" in dict
| True/False |
获取键 | dict.keys()
| list(dict.keys())
| 键列表 |
获取值 | dict.values()
| list(dict.values())
| 值列表 |
获取键值对 | dict.items()
| list(dict.items())
| 键值对列表 |
长度 | len(dict)
| len({"a":1})
| 1 |
更新 | dict.update()
| dict.update({"b":2})
| 合并字典 |
设置默认值 | dict.setdefault()
| dict.setdefault("c", 0)
| 设置默认值 |
复制 | dict.copy()
| new = dict.copy()
| 浅拷贝 |
🎉 恭喜!字典掌握完成现在你已经学会了Python中另一个极其重要的数据结构!
关键收获:
✅ 创建字典:四种方法创建字典
✅ 访问元素:通过键快速访问值
✅ 修改字典:增、删、改、查各种操作
✅ 遍历字典:遍历键、值、键值对
✅ 字典方法:丰富的内置方法
✅ 嵌套字典:处理复杂数据结构
✅ 实战应用:在测试中灵活使用字典
字典是自动化测试的核心,你会经常用它来:
存储测试配置
管理测试用例
处理接口请求/响应
组织测试数据
记录测试结果
下一章预告:元组和集合
准备好了吗?让我们继续前进!🚀
记住:字典要多用才能掌握。尝试用字典改写你之前的代码,看看能不能变得更结构化、更易维护。