【测试开发 Python 基础】P03 - 数据结构与常用操作
本文是《企业级自动化测试实战》系列的第 3 篇。上一篇我们学习了流程控制和函数,编写了 MallLite 的商品查询、搜索、分页、购物车等核心函数。本篇将深入讲解 Python 的四大核心数据结构,然后用它们为 MallLite 编写订单管理和数据统计模块。
前言
自动化测试中,几乎所有的操作都在和数据打交道:接口返回的是 JSON(本质是字典和列表的嵌套),Excel 读出来的是二维表格(列表套列表),断言时要从层层嵌套的响应中提取某个字段值。
如果数据结构不熟练,后面写自动化测试时会非常痛苦——光是 response["data"]["items"][0]["name"] 这种嵌套取值就能把人绕晕。
今天的任务:
- 深入掌握列表(list)的高级操作
- 深入掌握字典(dict)的高级操作
- 理解元组(tuple)和集合(set)
- 掌握字符串的更多技巧
- 为 MallLite 编写订单管理函数
- 为 MallLite 编写数据统计模块
一、列表 list 深入
列表是 Python 中最常用的数据结构,本质是一个有序的、可变的容器。
1.1 列表的创建
# 直接创建
fruits = ["苹果", "香蕉", "橘子"]
# 空列表
empty = []
# 用 range 生成数字列表
numbers = list(range(1, 11)) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 用列表推导式生成
squares = [x ** 2 for x in range(1, 6)] # [1, 4, 9, 16, 25]
1.2 列表的增删改查
products = ["iPhone", "MacBook", "iPad"]
# ====== 增 ======
products.append("AirPods") # 末尾追加 → ["iPhone", "MacBook", "iPad", "AirPods"]
products.insert(1, "Huawei") # 在索引 1 处插入 → ["iPhone", "Huawei", "MacBook", "iPad", "AirPods"]
products.extend(["Xiaomi", "OPPO"]) # 批量追加 → [..., "Xiaomi", "OPPO"]
# ====== 删 ======
products.remove("iPad") # 按值删除(删第一个匹配项)
last = products.pop() # 弹出最后一个元素并返回
products.pop(0) # 弹出索引 0 的元素
del products[0] # 删除索引 0 的元素
products.clear() # 清空列表
# ====== 改 ======
products = ["iPhone", "MacBook", "iPad"]
products[0] = "iPhone 15 Pro" # 修改索引 0 的元素
# ====== 查 ======
products = ["iPhone", "MacBook", "iPad", "MacBook"]
products.index("MacBook") # 1(第一次出现的位置)
products.count("MacBook") # 2(出现次数)
"iPad" in products # True(是否包含)
1.3 列表的排序
# 数字排序
prices = [8999, 5999, 399, 14999, 1899]
sorted(prices) # [399, 1899, 5999, 8999, 14999] 升序,不改变原列表
sorted(prices, reverse=True) # [14999, 8999, 5999, 1899, 399] 降序
prices.sort() # 原地排序,会改变原列表
prices.sort(reverse=True) # 原地降序
# 按指定规则排序(用 key 参数)
products = [
{"name": "iPhone", "price": 8999},
{"name": "iPad", "price": 4799},
{"name": "AirPods", "price": 1899},
]
# 按价格排序
by_price = sorted(products, key=lambda p: p["price"])
# → AirPods(1899), iPad(4799), iPhone(8999)
# 按价格降序
by_price_desc = sorted(products, key=lambda p: p["price"], reverse=True)
# → iPhone(8999), iPad(4799), AirPods(1899)
# 按名称长度排序
by_name_len = sorted(products, key=lambda p: len(p["name"]))
# → iPad(4), iPhone(6), AirPods(7)
lambda 是匿名函数的写法,lambda p: p["price"] 等价于:
def get_price(p):
return p["price"]
1.4 列表的切片
切片不仅能用于字符串,也能用于列表,语法相同:
items = ["a", "b", "c", "d", "e"]
items[1:3] # ["b", "c"] 取索引 1 到 2
items[:3] # ["a", "b", "c"] 前 3 个
items[2:] # ["c", "d", "e"] 从索引 2 到末尾
items[-2:] # ["d", "e"] 最后 2 个
items[::-1] # ["e", "d", "c", "b", "a"] 反转
# 实际场景:取列表前 10 条作为"热门商品"
top10 = products[:10]
# 复制列表(切片可以用来复制,避免引用问题)
original = [1, 2, 3]
copy = original[:] # 独立副本,修改 copy 不影响 original
1.5 嵌套列表
列表的元素可以是任何类型,包括列表本身:
# 二维列表:表格数据
order_items = [
["iPhone 15 Pro", 8999, 1],
["MacBook Pro 14", 14999, 1],
["AirPods Pro 2", 1899, 2],
]
# 取第一行第二列(第一个商品的价格)
order_items[0][1] # 8999
# 遍历嵌套列表
for item in order_items:
name = item[0]
price = item[1]
qty = item[2]
print(f" {name} × {qty} = ¥{price * qty}")
# 计算总价
total = sum(item[1] * item[2] for item in order_items)
在实际的接口测试中,响应数据通常是字典套列表再套字典的多层嵌套结构,需要熟练掌握层层取值。
二、字典 dict 深入
字典是 Python 中另一个核心数据结构,本质是键值对的无序集合。接口返回的 JSON 解析后就是字典。
2.1 字典的基本操作
user = {
"id": 1,
"username": "admin",
"role": "admin"
}
# ====== 查 ======
user["username"] # "admin"(键不存在会报 KeyError)
user.get("username") # "admin"(键不存在返回 None,推荐用这个)
user.get("age", 0) # 0(键不存在时返回默认值 0)
# ====== 增/改 ======
user["email"] = "admin@test.com" # 新增键值对
user["role"] = "superadmin" # 修改已有的值
# ====== 删 ======
del user["email"] # 删除键值对
email = user.pop("email", None) # 删除并返回值,键不存在返回 None
# ====== 判断 ======
"username" in user # True(判断键是否存在)
2.2 字典的遍历
user = {"id": 1, "username": "admin", "role": "admin"}
# 遍历键
for key in user:
print(key) # id, username, role
# 遍历值
for value in user.values():
print(value) # 1, admin, admin
# 遍历键值对(最常用)
for key, value in user.items():
print(f" {key}: {value}")
2.3 字典合并
# Python 3.9+ 用 | 运算符
base_config = {"timeout": 10, "retry": 3}
env_config = {"base_url": "http://test.com", "timeout": 30}
merged = base_config | env_config
# → {"timeout": 30, "retry": 3, "base_url": "http://test.com"}
# 注意:timeout 被后面的覆盖了
# 通用写法(兼容所有 Python 3 版本)
merged = {**base_config, **env_config}
# update 方法(会修改原字典)
base_config.update(env_config)
2.4 嵌套字典(重点)
接口返回的 JSON 通常是多层嵌套的字典,这是自动化测试中最常处理的数据结构:
# 模拟一个接口响应
response = {
"code": 200,
"message": "success",
"data": {
"total": 15,
"page": 1,
"items": [
{
"id": 1,
"name": "iPhone 15 Pro",
"price": 8999,
"specs": {
"color": "深空黑",
"storage": "256GB"
}
},
{
"id": 2,
"name": "iPhone 15",
"price": 5999,
"specs": {
"color": "蓝色",
"storage": "128GB"
}
}
]
}
}
# 层层取值
response["code"] # 200
response["data"]["total"] # 15
response["data"]["items"] # 商品列表
response["data"]["items"][0] # 第一个商品
response["data"]["items"][0]["name"] # "iPhone 15 Pro"
response["data"]["items"][0]["specs"]["color"] # "深空黑"
# 安全取值(避免 KeyError)
response.get("data", {}).get("items", []) # 如果 data 不存在返回空字典
response.get("data", {}).get("items", [])[0].get("name", "未知") # 链式安全取值
2.5 字典推导式
类似列表推导式,字典也有自己的推导式:
products = [
{"name": "iPhone", "price": 8999},
{"name": "iPad", "price": 4799},
{"name": "AirPods", "price": 1899},
]
# 生成 {商品名: 价格} 的映射
price_map = {p["name"]: p["price"] for p in products}
# → {"iPhone": 8999, "iPad": 4799, "AirPods": 1899}
# 筛选价格超过 3000 的
expensive = {p["name"]: p["price"] for p in products if p["price"] > 3000}
# → {"iPhone": 8999, "iPad": 4799}
三、元组 tuple
元组和列表很像,但有一个关键区别:元组不可变,创建后不能增删改。
# 创建元组
point = (100, 200)
rgb_color = (255, 128, 0)
# 访问元素(和列表一样用索引)
point[0] # 100
point[1] # 200
# ❌ 不能修改
# point[0] = 999 → 报错 TypeError
# 元组拆包
x, y = point
print(x) # 100
print(y) # 200
# 函数返回多个值时,实际返回的就是元组
def get_bounds(products):
prices = [p["price"] for p in products]
return min(prices), max(prices)
lowest, highest = get_bounds(products)
什么时候用元组而不是列表:当数据不应该被修改时用元组。比如坐标的 (x, y)、RGB 颜色值 (r, g, b)、数据库查询返回的一行记录等。
四、集合 set
集合是一个无序的、元素不重复的容器,最大的用途是去重和集合运算。
4.1 基本操作
# 创建集合
categories = {"手机", "笔记本", "平板", "配件"}
# 自动去重
names = ["iPhone", "iPad", "iPhone", "MacBook", "iPad"]
unique_names = set(names) # {"iPhone", "iPad", "MacBook"}
# 增删
categories.add("智能穿戴") # 添加
categories.discard("智能穿戴") # 删除(元素不存在不报错)
4.2 集合运算
# 假设两组用户的权限
admin_permissions = {"read", "write", "delete", "manage"}
user_permissions = {"read", "write"}
# 交集:都有哪些权限
both = admin_permissions & user_permissions # {"read", "write"}
# 并集:所有权限
all_perms = admin_permissions | user_permissions # {"read", "write", "delete", "manage"}
# 差集:admin 有但 user 没有的
admin_only = admin_permissions - user_permissions # {"delete", "manage"}
# 实际场景:找出新增的和删除的商品
old_products = {"iPhone 14", "iPhone 15", "MacBook Pro"}
new_products = {"iPhone 15", "iPhone 16", "MacBook Pro", "iPad Air"}
added = new_products - old_products # {"iPhone 16", "iPad Air"} 新增的
removed = old_products - new_products # {"iPhone 14"} 下架的
unchanged = old_products & new_products # {"iPhone 15", "MacBook Pro"} 没变的
五、字符串高级操作
5.1 join 拼接
# 把列表拼接成字符串(和 split 相反)
names = ["iPhone", "iPad", "MacBook"]
result = "、".join(names) # "iPhone、iPad、MacBook"
result = ", ".join(names) # "iPhone, iPad, MacBook"
result = "".join(names) # "iPhoneiPadMacBook"
# 实际场景:拼接 URL 路径
parts = ["api", "v1", "products", "123"]
url = "/".join(parts) # "api/v1/products/123"
5.2 strip / lstrip / rstrip
text = " Hello World "
text.strip() # "Hello World" 去除两边空格
text.lstrip() # "Hello World " 去除左边空格
text.rstrip() # " Hello World" 去除右边空格
# 也能去除指定字符
price_str = "¥999元"
price_str.strip("¥元") # "999"
5.3 zfill 补零
# 给数字前面补零,常用于生成编号
order_id = str(1).zfill(6) # "000001"
order_id = str(42).zfill(6) # "000042"
order_id = str(12345).zfill(6) # "012345"
5.4 isdigit / isalpha / isalnum
"12345".isdigit() # True(全是数字)
"hello".isalpha() # True(全是字母)
"hello123".isalnum() # True(全是字母或数字)
"".isspace() # False
" ".isspace() # True(全是空白字符)
# 实际场景:验证用户输入
username = "admin123"
if username.isalnum():
print("用户名格式正确")
else:
print("用户名只能包含字母和数字")
5.5 多行字符串与文本处理
# 多行文本处理
log_text = """
[2024-01-15 10:30:01] INFO: 用户 admin 登录成功
[2024-01-15 10:30:05] INFO: 查询商品列表,返回 15 条
[2024-01-15 10:30:10] ERROR: 创建订单失败,购物车为空
[2024-01-15 10:30:15] INFO: 用户 vipuser 登录成功
"""
# 按行分割并去除空行
lines = [line.strip() for line in log_text.strip().split("\n") if line.strip()]
# 筛选 ERROR 日志
errors = [line for line in lines if "ERROR" in line]
print(f"发现 {len(errors)} 条错误日志:")
for err in errors:
print(f" {err}")
六、动手实战:订单管理函数
创建新文件 order_functions.py,编写 MallLite 的订单管理模块。
"""
MallLite 电商系统 - 订单管理与数据统计
功能:订单创建、查询、取消、数据统计分析
"""
import json
import os
from datetime import datetime
# ========================================
# 加载数据
# ========================================
data_dir = "data"
def load_json(filename):
"""加载 JSON 数据文件"""
filepath = os.path.join(data_dir, filename)
with open(filepath, "r", encoding="utf-8") as f:
return json.load(f)
products = load_json("products.json")
users = load_json("users.json")
# 复用上一篇的函数
def get_product_by_id(product_id):
"""根据 ID 查询商品"""
for p in products:
if p["id"] == product_id:
return p
return None
print(f"加载完成:{len(products)} 个商品,{len(users)} 个用户")
print("=" * 60)
# ========================================
# 第一部分:订单管理
# ========================================
# 订单列表(内存中维护)
orders = []
# 订单号计数器
order_counter = 0
def generate_order_no():
"""
生成订单号:ORD + 日期 + 6 位序号
例如:ORD20240115-000001
"""
global order_counter
order_counter += 1
date_str = datetime.now().strftime("%Y%m%d")
seq = str(order_counter).zfill(6)
return f"ORD{date_str}-{seq}"
def create_order(user_id, cart_items):
"""
从购物车创建订单
参数:
user_id: 用户 ID
cart_items: 购物车商品列表,每个元素格式:
{"product_id": 1, "quantity": 2}
返回:
创建结果字典,包含 success、message、order
"""
# 验证购物车是否为空
if not cart_items:
return {"success": False, "message": "购物车为空,无法创建订单", "order": None}
# 构建订单商品明细
order_items = []
total_price = 0
for cart_item in cart_items:
product_id = cart_item["product_id"]
quantity = cart_item["quantity"]
# 查找商品
product = get_product_by_id(product_id)
if product is None:
return {"success": False, "message": f"商品 ID={product_id} 不存在", "order": None}
# 检查库存
if product["stock"] < quantity:
return {
"success": False,
"message": f"{product['name']} 库存不足(需要 {quantity},剩余 {product['stock']})",
"order": None
}
# 构建订单项
subtotal = product["price"] * quantity
order_items.append({
"product_id": product_id,
"name": product["name"],
"price": product["price"],
"quantity": quantity,
"subtotal": subtotal
})
total_price += subtotal
# 扣减库存
for cart_item in cart_items:
product = get_product_by_id(cart_item["product_id"])
product["stock"] -= cart_item["quantity"]
# 创建订单
order_no = generate_order_no()
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
order = {
"order_no": order_no,
"user_id": user_id,
"items": order_items,
"total_price": total_price,
"item_count": len(order_items),
"total_quantity": sum(item["quantity"] for item in order_items),
"status": "待支付",
"created_at": now,
"updated_at": now
}
orders.append(order)
return {"success": True, "message": f"订单 {order_no} 创建成功", "order": order}
def get_order_list(user_id=None, status=None):
"""
获取订单列表,支持按用户和状态筛选
参数:
user_id: 用户 ID(可选,不传则返回所有订单)
status: 订单状态(可选,如 "待支付"、"已取消")
返回:
符合条件的订单列表
"""
result = orders
if user_id is not None:
result = [o for o in result if o["user_id"] == user_id]
if status is not None:
result = [o for o in result if o["status"] == status]
return result
def get_order_by_no(order_no):
"""
根据订单号查询订单
参数:
order_no: 订单号
返回:
找到返回订单字典,找不到返回 None
"""
for order in orders:
if order["order_no"] == order_no:
return order
return None
def cancel_order(order_no):
"""
取消订单(恢复库存)
参数:
order_no: 订单号
返回:
操作结果字典
"""
order = get_order_by_no(order_no)
if order is None:
return {"success": False, "message": f"订单 {order_no} 不存在"}
if order["status"] == "已取消":
return {"success": False, "message": f"订单 {order_no} 已经是取消状态"}
if order["status"] == "已完成":
return {"success": False, "message": f"订单 {order_no} 已完成,无法取消"}
# 恢复库存
for item in order["items"]:
product = get_product_by_id(item["product_id"])
if product:
product["stock"] += item["quantity"]
order["status"] = "已取消"
order["updated_at"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
return {"success": True, "message": f"订单 {order_no} 已取消,库存已恢复"}
def pay_order(order_no):
"""
支付订单
参数:
order_no: 订单号
返回:
操作结果字典
"""
order = get_order_by_no(order_no)
if order is None:
return {"success": False, "message": f"订单 {order_no} 不存在"}
if order["status"] != "待支付":
return {"success": False, "message": f"订单 {order_no} 状态为 {order['status']},无法支付"}
order["status"] = "已支付"
order["updated_at"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
return {"success": True, "message": f"订单 {order_no} 支付成功,金额 ¥{order['total_price']}"}
def print_order(order):
"""美观地打印订单详情"""
print(f" 订单号:{order['order_no']}")
print(f" 状态:{order['status']}")
print(f" 下单时间:{order['created_at']}")
print(f" 商品明细:")
for item in order["items"]:
print(f" - {item['name']} ¥{item['price']} × {item['quantity']} = ¥{item['subtotal']}")
print(f" 合计:{order['total_quantity']} 件,¥{order['total_price']}")
# ========================================
# 测试订单管理
# ========================================
print("\n【订单管理功能】")
print("-" * 60)
# 模拟登录用户
current_user = users[1] # testuser
print(f"\n当前用户:{current_user['nickname']}(ID={current_user['id']})")
# 订单 1:正常下单
print("\n1. 创建订单 1(正常下单):")
cart1 = [
{"product_id": 1, "quantity": 1}, # iPhone 15 Pro × 1
{"product_id": 11, "quantity": 2}, # AirPods Pro 2 × 2
]
result = create_order(current_user["id"], cart1)
print(f" {result['message']}")
if result["success"]:
print_order(result["order"])
order1_no = result["order"]["order_no"]
# 订单 2:另一笔订单
print("\n2. 创建订单 2(购买笔记本):")
cart2 = [
{"product_id": 5, "quantity": 1}, # MacBook Pro 14 × 1
]
result = create_order(current_user["id"], cart2)
print(f" {result['message']}")
if result["success"]:
print_order(result["order"])
order2_no = result["order"]["order_no"]
# 订单 3:库存不足
print("\n3. 测试库存不足:")
cart3 = [{"product_id": 5, "quantity": 999}]
result = create_order(current_user["id"], cart3)
print(f" {result['message']}")
# 订单 4:空购物车
print("\n4. 测试空购物车下单:")
result = create_order(current_user["id"], [])
print(f" {result['message']}")
# 支付订单 1
print("\n5. 支付订单 1:")
result = pay_order(order1_no)
print(f" {result['message']}")
# 取消订单 2
print("\n6. 取消订单 2:")
result = cancel_order(order2_no)
print(f" {result['message']}")
# 查看当前用户所有订单
print(f"\n7. {current_user['nickname']} 的所有订单:")
user_orders = get_order_list(user_id=current_user["id"])
for order in user_orders:
print(f" - {order['order_no']} | {order['status']} | ¥{order['total_price']}")
# 按状态筛选
print(f"\n8. 筛选已支付的订单:")
paid_orders = get_order_list(status="已支付")
for order in paid_orders:
print(f" - {order['order_no']} | ¥{order['total_price']}")
print()
# ========================================
# 第二部分:数据统计分析
# ========================================
print("【数据统计分析】")
print("=" * 60)
# ========================================
# 统计 1:各分类商品数量和平均价格
# ========================================
print("\n统计 1:各分类商品统计")
print("-" * 60)
def analyze_categories(products):
"""
统计各分类的商品数量、平均价格、最高价、最低价
参数:
products: 商品列表
返回:
各分类的统计数据字典
"""
stats = {}
for p in products:
cat = p["category"]
if cat not in stats:
stats[cat] = {
"count": 0,
"total_price": 0,
"prices": [],
"names": []
}
stats[cat]["count"] += 1
stats[cat]["total_price"] += p["price"]
stats[cat]["prices"].append(p["price"])
stats[cat]["names"].append(p["name"])
# 计算统计值
for cat, data in stats.items():
data["avg_price"] = data["total_price"] / data["count"]
data["min_price"] = min(data["prices"])
data["max_price"] = max(data["prices"])
# 删除临时字段,只保留统计数据
del data["prices"]
return stats
category_stats = analyze_categories(products)
# 用格式化对齐输出
print(f" {'分类':<8} {'数量':>4} {'平均价':>8} {'最低价':>8} {'最高价':>8}")
print(f" {'—' * 40}")
for cat, data in category_stats.items():
print(f" {cat:<8} {data['count']:>4} {data['avg_price']:>8.0f} {data['min_price']:>8} {data['max_price']:>8}")
# ========================================
# 统计 2:价格区间分布
# ========================================
print(f"\n统计 2:价格区间分布")
print("-" * 60)
def analyze_price_distribution(products):
"""
统计商品在各价格区间的分布
参数:
products: 商品列表
返回:
各区间的商品数量和占比
"""
ranges = [
("¥0-500", 0, 500),
("¥500-2000", 500, 2000),
("¥2000-5000", 2000, 5000),
("¥5000-10000", 5000, 10000),
("¥10000+", 10000, float("inf")),
]
total = len(products)
distribution = []
for label, low, high in ranges:
count = len([p for p in products if low <= p["price"] < high])
percentage = count / total * 100 if total > 0 else 0
distribution.append({
"range": label,
"count": count,
"percentage": percentage,
"names": [p["name"] for p in products if low <= p["price"] < high]
})
return distribution
distribution = analyze_price_distribution(products)
for item in distribution:
bar = "█" * int(item["percentage"] / 5) # 每 5% 一个方块
print(f" {item['range']:<12} {item['count']:>2} 个 ({item['percentage']:>5.1f}%) {bar}")
# ========================================
# 统计 3:库存预警
# ========================================
print(f"\n统计 3:库存预警(低于 80 件)")
print("-" * 60)
def get_stock_alerts(products, threshold=80):
"""
获取库存预警商品
参数:
products: 商品列表
threshold: 库存阈值
返回:
低于阈值的商品列表,按库存从低到高排序
"""
alerts = [p for p in products if p["stock"] < threshold]
return sorted(alerts, key=lambda p: p["stock"])
alerts = get_stock_alerts(products, threshold=80)
if alerts:
for p in alerts:
level = "🔴 紧急" if p["stock"] < 50 else "🟡 预警"
print(f" {level} {p['name']:<20} 仅剩 {p['stock']} 件")
else:
print(" 所有商品库存充足")
# ========================================
# 统计 4:新品与非新品对比
# ========================================
print(f"\n统计 4:新品 vs 非新品")
print("-" * 60)
def compare_new_vs_old(products):
"""
对比新品和非新品的数量、平均价格、平均评分
返回:
包含新品和非新品统计数据的字典
"""
new_items = [p for p in products if p["is_new"]]
old_items = [p for p in products if not p["is_new"]]
def calc_stats(items, label):
if not items:
return {"label": label, "count": 0, "avg_price": 0, "avg_rating": 0}
return {
"label": label,
"count": len(items),
"avg_price": sum(p["price"] for p in items) / len(items),
"avg_rating": sum(p["rating"] for p in items) / len(items),
}
return calc_stats(new_items, "新品"), calc_stats(old_items, "非新品")
new_stats, old_stats = compare_new_vs_old(products)
print(f" {'类型':<8} {'数量':>4} {'平均价格':>10} {'平均评分':>8}")
print(f" {'—' * 36}")
for stats in [new_stats, old_stats]:
print(f" {stats['label']:<8} {stats['count']:>4} {stats['avg_price']:>10.0f} {stats['avg_rating']:>8.1f}")
# ========================================
# 统计 5:订单统计(如果有订单数据)
# ========================================
print(f"\n统计 5:订单统计")
print("-" * 60)
def analyze_orders(order_list):
"""
统计订单数据
参数:
order_list: 订单列表
返回:
订单统计数据字典
"""
if not order_list:
return {
"total_orders": 0,
"total_revenue": 0,
"avg_order_price": 0,
"status_distribution": {},
"top_products": []
}
# 按状态统计
status_count = {}
for order in order_list:
status = order["status"]
if status not in status_count:
status_count[status] = 0
status_count[status] += 1
# 计算总收入(只统计已支付的订单)
paid_orders = [o for o in order_list if o["status"] == "已支付"]
total_revenue = sum(o["total_price"] for o in paid_orders)
# 统计商品销量
product_sales = {}
for order in order_list:
if order["status"] != "已取消":
for item in order["items"]:
name = item["name"]
if name not in product_sales:
product_sales[name] = 0
product_sales[name] += item["quantity"]
# 按销量排序取前 5
top_products = sorted(product_sales.items(), key=lambda x: x[1], reverse=True)[:5]
return {
"total_orders": len(order_list),
"total_revenue": total_revenue,
"avg_order_price": total_revenue / len(paid_orders) if paid_orders else 0,
"status_distribution": status_count,
"top_products": top_products
}
order_stats = analyze_orders(orders)
print(f" 总订单数:{order_stats['total_orders']}")
print(f" 已支付收入:¥{order_stats['total_revenue']}")
print(f" 平均客单价:¥{order_stats['avg_order_price']:.0f}")
print(f" 状态分布:")
for status, count in order_stats["status_distribution"].items():
print(f" {status}:{count} 笔")
if order_stats["top_products"]:
print(f" 销量 Top 商品:")
for name, qty in order_stats["top_products"]:
print(f" {name}:{qty} 件")
# ========================================
# 统计 6:用字典推导式做快速统计
# ========================================
print(f"\n统计 6:字典推导式快速统计")
print("-" * 60)
# 商品名 → 价格 映射
price_map = {p["name"]: p["price"] for p in products}
print(f" 商品价格映射(前 5 个):")
for i, (name, price) in enumerate(price_map.items()):
if i >= 5:
break
print(f" {name} → ¥{price}")
# 各分类最低价商品
cheapest_by_category = {}
for p in products:
cat = p["category"]
if cat not in cheapest_by_category or p["price"] < cheapest_by_category[cat]["price"]:
cheapest_by_category[cat] = p
print(f"\n 各分类最低价商品:")
for cat, p in cheapest_by_category.items():
print(f" {cat}:{p['name']}(¥{p['price']})")
# ========================================
# 总结
# ========================================
print(f"\n{'=' * 60}")
print("本次编写了以下函数和统计模块:")
print("=" * 60)
functions = [
("generate_order_no()", "生成订单号"),
("create_order(user_id, cart_items)", "创建订单"),
("get_order_list(user_id, status)", "获取订单列表(支持筛选)"),
("get_order_by_no(order_no)", "根据订单号查询"),
("cancel_order(order_no)", "取消订单(恢复库存)"),
("pay_order(order_no)", "支付订单"),
("print_order(order)", "打印订单详情"),
("analyze_categories(products)", "各分类商品统计"),
("analyze_price_distribution(products)", "价格区间分布"),
("get_stock_alerts(products, threshold)", "库存预警"),
("compare_new_vs_old(products)", "新品 vs 非新品对比"),
("analyze_orders(order_list)", "订单统计"),
]
for func_name, desc in functions:
print(f" {func_name:<48} # {desc}")
print(f"\n数据结构使用统计:")
usage = [
("列表 list", "商品列表、订单列表、购物车、统计结果"),
("字典 dict", "商品信息、订单信息、配置、统计映射"),
("集合 set", "分类去重、权限对比"),
("元组 tuple", "函数多返回值、价格区间定义"),
("列表推导式", "筛选商品、提取字段、数据转换"),
("字典推导式", "价格映射、最低价统计"),
("嵌套结构", "订单包含商品列表,每个商品又是一个字典"),
]
for struct, usage_desc in usage:
print(f" {struct:<16} → {usage_desc}")
运行脚本
python order_functions.py
完整输出
加载完成:15 个商品,3 个用户
============================================================
【订单管理功能】
------------------------------------------------------------
当前用户:测试用户(ID=2)
1. 创建订单 1(正常下单):
订单 ORD20240115-000001 创建成功
订单号:ORD20240115-000001
状态:待支付
下单时间:2024-01-15 10:30:01
商品明细:
- iPhone 15 Pro ¥8999 × 1 = ¥8999
- AirPods Pro 2 ¥1899 × 2 = ¥3798
合计:3 件,¥12797
2. 创建订单 2(购买笔记本):
订单 ORD20240115-000002 创建成功
订单号:ORD20240115-000002
状态:待支付
下单时间:2024-01-15 10:30:02
商品明细:
- MacBook Pro 14 ¥14999 × 1 = ¥14999
合计:1 件,¥14999
3. 测试库存不足:
MacBook Pro 14 库存不足(需要 999,剩余 49)
4. 测试空购物车下单:
购物车为空,无法创建订单
5. 支付订单 1:
订单 ORD20240115-000001 支付成功,金额 ¥12797
6. 取消订单 2:
订单 ORD20240115-000002 已取消,库存已恢复
7. 测试用户的所有订单:
- ORD20240115-000001 | 已支付 | ¥12797
- ORD20240115-000002 | 已取消 | ¥14999
8. 筛选已支付的订单:
- ORD20240115-000001 | ¥12797
【数据统计分析】
============================================================
统计 1:各分类商品统计
------------------------------------------------------------
分类 数量 平均价 最低价 最高价
————————————————————————————————————————
手机 4 6749 4999 8999
笔记本 3 11332 8999 14999
平板 3 5932 3999 8999
配件 5 1219 199 3299
统计 2:价格区间分布
------------------------------------------------------------
¥0-500 3 个 ( 20.0%) ████
¥500-2000 1 个 ( 6.7%) █
¥2000-5000 3 个 ( 20.0%) ████
¥5000-10000 5 个 ( 33.3%) ██████
¥10000+ 3 个 ( 20.0%) ████
统计 3:库存预警(低于 80 件)
------------------------------------------------------------
🔴 紧急 华为 MateBook X Pro 仅剩 45 件
🔴 紧急 MacBook Pro 14 仅剩 49 件
🟡 预警 华为 Mate 60 Pro 仅剩 79 件
🟡 预警 iPad Pro 12.9 仅剩 69 件
统计 4:新品 vs 非新品
------------------------------------------------------------
类型 数量 平均价格 平均评分
————————————————————————————————————
新品 6 6549 4.7
非新品 9 4343 4.5
统计 5:订单统计
------------------------------------------------------------
总订单数:2
已支付收入:¥12797
平均客单价:¥12797
状态分布:
已支付:1 笔
已取消:1 笔
销量 Top 商品:
iPhone 15 Pro:1 件
AirPods Pro 2:2 件
MacBook Pro 14:1 件
统计 6:字典推导式快速统计
------------------------------------------------------------
商品价格映射(前 5 个):
iPhone 15 Pro → ¥8999
iPhone 15 → ¥5999
华为 Mate 60 Pro → ¥6999
小米 14 Pro → ¥4999
MacBook Pro 14 → ¥14999
各分类最低价商品:
手机:小米 14 Pro(¥4999)
笔记本:华为 MateBook X Pro(¥8999)
平板:华为 MatePad Pro(¥3999)
配件:USB-C 转接头(¥199)
============================================================
本次编写了以下函数和统计模块:
============================================================
generate_order_no() # 生成订单号
create_order(user_id, cart_items) # 创建订单
get_order_list(user_id, status) # 获取订单列表(支持筛选)
get_order_by_no(order_no) # 根据订单号查询
cancel_order(order_no) # 取消订单(恢复库存)
pay_order(order_no) # 支付订单
print_order(order) # 打印订单详情
analyze_categories(products) # 各分类商品统计
analyze_price_distribution(products) # 价格区间分布
get_stock_alerts(products, threshold) # 库存预警
compare_new_vs_old(products) # 新品 vs 非新品对比
analyze_orders(order_list) # 订单统计
数据结构使用统计:
列表 list → 商品列表、订单列表、购物车、统计结果
字典 dict → 商品信息、订单信息、配置、统计映射
集合 set → 分类去重、权限对比
元组 tuple → 函数多返回值、价格区间定义
列表推导式 → 筛选商品、提取字段、数据转换
字典推导式 → 价格映射、最低价统计
嵌套结构 → 订单包含商品列表,每个商品又是一个字典
七、本篇用到的数据结构知识总结
| 数据结构 | 特点 | 本篇的应用场景 |
|---|---|---|
| 列表 list | 有序、可变、可重复 | 商品列表、订单列表、购物车、统计结果列表 |
| 字典 dict | 键值对、无序、键不重复 | 商品信息、订单信息、统计数据、价格映射 |
| 元组 tuple | 有序、不可变 | 价格区间定义 (low, high)、函数返回多个值 |
| 集合 set | 无序、不重复 | 分类去重、新旧商品对比 |
| 列表推导式 | 一行代码完成筛选和转换 | 筛选低价商品、提取商品名列表 |
| 字典推导式 | 一行代码生成键值映射 | 商品名到价格的映射 |
| 嵌套结构 | 字典套列表再套字典 | 订单结构(订单 → 商品列表 → 每个商品的详情) |
八、课后练习
练习 1:添加订单搜索函数
def search_orders(keyword):
"""
搜索订单(在订单号和商品名中搜索关键词)
参数:
keyword: 搜索关键词
返回:
匹配的订单列表
"""
results = []
for order in orders:
# 在订单号中搜索
if keyword in order["order_no"]:
results.append(order)
continue
# 在商品名中搜索
for item in order["items"]:
if keyword in item["name"]:
results.append(order)
break
return results
# 测试
results = search_orders("iPhone")
print(f"搜索 'iPhone',找到 {len(results)} 笔订单")
练习 2:添加商品销量排行函数
def get_sales_ranking(order_list, top_n=5):
"""
根据已支付订单统计商品销量排行
参数:
order_list: 订单列表
top_n: 返回前 N 名
返回:
销量排行列表,每项包含商品名和销量
"""
sales = {}
for order in order_list:
if order["status"] in ["已支付", "待支付"]:
for item in order["items"]:
name = item["name"]
sales[name] = sales.get(name, 0) + item["quantity"]
ranking = sorted(sales.items(), key=lambda x: x[1], reverse=True)
return ranking[:top_n]
ranking = get_sales_ranking(orders, top_n=3)
print("销量排行:")
for i, (name, qty) in enumerate(ranking, 1):
print(f" 第 {i} 名:{name}({qty} 件)")
练习 3:添加用户消费统计函数
def get_user_spending(order_list, user_id):
"""
统计某个用户的消费情况
返回:
包含订单数、总消费、已支付消费、平均客单价的字典
"""
user_orders = [o for o in order_list if o["user_id"] == user_id]
paid_orders = [o for o in user_orders if o["status"] == "已支付"]
return {
"total_orders": len(user_orders),
"total_spending": sum(o["total_price"] for o in paid_orders),
"avg_order_price": sum(o["total_price"] for o in paid_orders) / len(paid_orders) if paid_orders else 0,
"paid_orders": len(paid_orders),
"cancelled_orders": len([o for o in user_orders if o["status"] == "已取消"])
}
stats = get_user_spending(orders, user_id=2)
print(f"用户消费统计:{stats}")
九、今日成果总结
今天完成了什么:
- 深入学习了列表的排序、切片、嵌套操作
- 深入学习了字典的嵌套取值、合并、推导式
- 理解了元组和集合的适用场景
- 学习了字符串的高级操作(join、strip、zfill 等)
- 编写了完整的订单管理模块(创建、查询、支付、取消)
- 编写了 6 个数据统计分析函数
- 综合运用了所有数据结构知识
当前项目结构:
mall-lite/
├── data/
│ ├── products.json ← 15 个商品
│ ├── categories.json ← 4 个分类
│ └── users.json ← 3 个用户
├── generate_data.py ← P01:数据生成脚本
├── mall_functions.py ← P02:核心业务函数(查询、搜索、分页、购物车)
├── order_functions.py ← P03:订单管理与数据统计(本篇)
├── hello.py
└── venv/
十、下篇预告
P04 - 文件操作与异常处理
下一篇将学习 JSON、YAML、CSV、Excel 文件的读写操作,以及 try/except 异常处理机制。然后用这些知识为 MallLite 编写一个完整的数据存储层(DataStore),把之前散落各处的数据操作统一封装,为 P05 搭建 FastAPI 后端做好准备。
系列导航
| 序号 | 标题 | 状态 |
|---|---|---|
| P01 | Python 环境搭建与第一行代码 | ✅ 已发布 |
| P02 | 流程控制与函数 | ✅ 已发布 |
| P03 | 数据结构与常用操作 | ✅ 本文 |
| P04 | 文件操作与异常处理 | 下一篇 |
| P05 | 面向对象与模块 | 待更新 |
| P06 | 自动化测试常用技巧 | 待更新 |
| 01 | Web UI 自动化项目总览与环境搭建 | 待更新 |
| 02 | 框架基础层搭建 | 待更新 |
更多推荐




所有评论(0)