本文是《企业级自动化测试实战》系列的第 2 篇。上一篇我们搭建了 Python 环境并生成了 MallLite 项目的商品数据。本篇将学习条件判断、循环和函数,然后用它们为 MallLite 编写商品查询、搜索、分页等核心逻辑。


前言

上一篇我们用变量和数据类型生成了商品数据文件。但数据生成出来只是放在那里,真正的项目需要对数据进行操作:查找某个商品、按分类筛选、分页展示、计算总价……

这些操作都需要用到两个核心能力:流程控制(告诉程序在什么情况下做什么)和函数(把一段可复用的逻辑包起来)。

今天的任务:

  • 掌握 if / elif / else 条件判断
  • 掌握 for / while 循环
  • 学会定义和调用函数
  • 学会函数的参数和返回值
  • 为 MallLite 编写商品查询、搜索、分页函数
  • 学会列表推导式(Python 最优雅的特性之一)

一、条件判断 if / elif / else

1.1 基本语法

程序需要根据不同情况执行不同的代码。比如:库存大于 0 显示"有货",否则显示"缺货"。

stock = 50

if stock > 0:
    print("有货")
else:
    print("缺货")

# 输出:有货

注意两点:

  • 条件后面要加冒号 :
  • 代码块要缩进 4 个空格(Python 用缩进表示代码层级,不用大括号)

1.2 多条件判断 elif

如果需要判断多个条件,用 elif(else if 的缩写):

price = 8999

if price < 500:
    print("低价商品")
elif price < 2000:
    print("中价商品")
elif price < 5000:
    print("高价商品")
else:
    print("奢侈品")

# 输出:奢侈品

判断顺序从上到下,一旦某个条件成立,执行对应的代码块,后面的 elif 和 else 全部跳过。

1.3 条件表达式

常用的比较运算符:

运算符含义示例
==等于price == 999
!=不等于status != "sold_out"
>大于stock > 0
<小于price < 1000
>=大于等于rating >= 4.5
<=小于等于quantity <= 0
in包含"iPhone" in name
not in不包含"测试" not in name

1.4 逻辑运算符

多个条件组合:

# and:两个条件都满足
if price > 1000 and stock > 0:
    print("高价且有货的商品")

# or:满足其中一个
if category == "手机" or category == "平板":
    print("移动设备")

# not:取反
if not is_new:
    print("非新品")

1.5 用在 MallLite 的场景

# 根据价格区间给商品打标签
price = 8999

if price < 500:
    tag = "平价"
elif price < 3000:
    tag = "中端"
elif price < 8000:
    tag = "高端"
else:
    tag = "旗舰"

print(f"¥{price} 属于:{tag}商品")
# 输出:¥8999 属于:旗舰商品

二、循环 for / while

2.1 for 循环

for 循环用来遍历一个序列(列表、字符串、range 等):

# 遍历列表
fruits = ["苹果", "香蕉", "橘子"]
for fruit in fruits:
    print(f"我喜欢吃{fruit}")

# 输出:
# 我喜欢吃苹果
# 我喜欢吃香蕉
# 我喜欢吃橘子

2.2 range() 函数

range() 生成一个数字序列,常用于循环指定次数:

# range(5) 生成 0, 1, 2, 3, 4
for i in range(5):
    print(i)

# range(1, 6) 生成 1, 2, 3, 4, 5
for i in range(1, 6):
    print(f"第 {i} 页")

# range(0, 20, 5) 生成 0, 5, 10, 15(步长为 5)
for i in range(0, 20, 5):
    print(i)

2.3 带索引的遍历

有时候不仅需要元素,还需要它的位置(索引)。用 enumerate()

products = ["iPhone", "MacBook", "iPad"]

for index, name in enumerate(products):
    print(f"  {index + 1}. {name}")

# 输出:
#   1. iPhone
#   2. MacBook
#   3. iPad

2.4 while 循环

while 循环在条件为真时一直执行

# 翻页示例:从第 1 页翻到最后一页
page = 1
total_pages = 5

while page <= total_pages:
    print(f"正在加载第 {page} 页...")
    page = page + 1

print("所有页面加载完成")

# 输出:
# 正在加载第 1 页...
# 正在加载第 2 页...
# 正在加载第 3 页...
# 正在加载第 4 页...
# 正在加载第 5 页...
# 所有页面加载完成

2.5 break 和 continue

break:立即跳出整个循环。

# 找到第一个价格低于 1000 的商品就停止
prices = [8999, 5999, 6999, 4999, 399, 1899]

for price in prices:
    if price < 1000:
        print(f"找到低价商品:¥{price}")
        break
    print(f"¥{price} 太贵了,跳过")

# 输出:
# ¥8999 太贵了,跳过
# ¥5999 太贵了,跳过
# ¥6999 太贵了,跳过
# ¥4999 太贵了,跳过
# 找到低价商品:¥399

continue:跳过本次循环,继续下一次。

# 打印所有有库存的商品,跳过缺货的
products = [
    {"name": "iPhone", "stock": 100},
    {"name": "MacBook", "stock": 0},
    {"name": "iPad", "stock": 50},
    {"name": "AirPods", "stock": 0},
]

for p in products:
    if p["stock"] == 0:
        continue  # 跳过缺货商品
    print(f"有货:{p['name']}(库存 {p['stock']})")

# 输出:
# 有货:iPhone(库存 100)
# 有货:iPad(库存 50)

2.6 循环中的 else

Python 独有的语法:for/while 循环正常结束(没有被 break 中断)时,执行 else 块。

# 搜索商品,如果遍历完都没找到,提示未找到
products = ["iPhone", "MacBook", "iPad"]
keyword = "华为"

for name in products:
    if keyword in name:
        print(f"找到:{name}")
        break
else:
    print(f"未找到包含'{keyword}'的商品")

# 输出:未找到包含'华为'的商品

三、列表推导式(Python 最优雅的写法)

列表推导式是 Python 的招牌特性,一行代码就能完成"遍历 + 筛选 + 转换"。在后面的自动化测试代码中会大量使用。

3.1 基本语法

# 普通写法:获取所有商品名
names = []
for p in products:
    names.append(p["name"])

# 列表推导式:一行搞定
names = [p["name"] for p in products]

3.2 带条件筛选

# 筛选价格低于 5000 的商品名
cheap = [p["name"] for p in products if p["price"] < 5000]

# 筛选所有手机类商品
phones = [p for p in products if p["category"] == "手机"]

# 筛选新品
new_products = [p["name"] for p in products if p["is_new"]]

3.3 转换数据

# 获取所有价格并转成字符串
price_strings = [f"¥{p['price']}" for p in products]

# 生成商品摘要
summaries = [f"{p['name']}(¥{p['price']})" for p in products]

3.4 对比普通写法和列表推导式

需求普通写法列表推导式
获取所有商品名names = []
for p in products:
names.append(p["name"])
[p["name"] for p in products]
筛选手机phones = []
for p in products:
if p["category"] == "手机":
phones.append(p)
[p for p in products if p["category"] == "手机"]
获取所有价格prices = []
for p in products:
prices.append(p["price"])
[p["price"] for p in products]

列表推导式可读性更高,代码更短,是 Pythonic 的写法。


四、函数

4.1 为什么要用函数

假设你在 10 个地方都需要"根据 ID 查找商品"这个逻辑。不用函数的话,同样的代码要写 10 遍。有了函数,写一次,到处调用。

# 没有函数:重复代码
# 在搜索功能中
for p in products:
    if p["id"] == 3:
        print(p["name"])

# 在购物车功能中
for p in products:
    if p["id"] == 3:
        print(p["price"])

# 在订单功能中
for p in products:
    if p["id"] == 3:
        print(p["stock"])

# 有函数:写一次,用三次
def get_product_by_id(product_id):
    for p in products:
        if p["id"] == product_id:
            return p
    return None

product = get_product_by_id(3)
print(product["name"])
print(product["price"])
print(product["stock"])

4.2 定义函数的基本语法

def 函数名(参数1, 参数2):
    """函数说明(可选)"""
    # 函数体
    return 返回值

一个最简单的例子:

def greet(name):
    """打招呼函数"""
    return f"你好,{name}!"

# 调用函数
message = greet("张三")
print(message)  # 输出:你好,张三!

4.3 参数类型

# 位置参数(最常用)
def add(a, b):
    return a + b

result = add(3, 5)  # a=3, b=5

# 默认参数(有默认值,调用时可以省略)
def greet(name, greeting="你好"):
    return f"{greeting}{name}!"

greet("张三")           # "你好,张三!"
greet("张三", "早上好")   # "早上好,张三!"

# 关键字参数(指定参数名,顺序随意)
def create_user(username, age, role="user"):
    return {"username": username, "age": age, "role": role}

create_user(age=25, username="张三")           # 顺序随意
create_user("张三", 25, role="admin")          # 指定 role

4.4 返回值

# 返回单个值
def get_price(product):
    return product["price"]

# 返回多个值(实际上返回一个元组)
def get_price_range(products):
    prices = [p["price"] for p in products]
    return min(prices), max(prices)

lowest, highest = get_price_range(products)
print(f"价格区间:¥{lowest} - ¥{highest}")

# 返回字典
def get_product_summary(product):
    return {
        "name": product["name"],
        "price": product["price"],
        "in_stock": product["stock"] > 0
    }

# 没有 return 或 return 后没有值,返回 None
def print_product(product):
    print(product["name"])
    # 隐式返回 None

4.5 函数文档字符串

函数体的第一行用三引号写的字符串,就是这个函数的说明文档。好的文档字符串能让别人(包括未来的你)快速理解函数的用途:

def search_products(products, keyword):
    """
    根据关键词搜索商品(模糊匹配名称)

    参数:
        products: 商品列表
        keyword: 搜索关键词

    返回:
        包含关键词的商品列表
    """
    return [p for p in products if keyword.lower() in p["name"].lower()]

在 IDE 中调用函数时,鼠标悬停就能看到这段说明。


五、动手实战:为 MallLite 编写核心函数

学完以上知识,现在来为 MallLite 项目编写一组核心函数。

创建新文件 mall_functions.py

"""
MallLite 电商系统 - 核心业务函数
功能:商品查询、搜索、筛选、分页、购物车、用户验证
"""

import json
import os

# ========================================
# 第一步:加载数据
# ========================================
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")
categories = load_json("categories.json")

print(f"加载完成:{len(products)} 个商品,{len(users)} 个用户,{len(categories)} 个分类")
print("=" * 60)


# ========================================
# 第二步:商品查询函数
# ========================================

def get_product_by_id(product_id):
    """
    根据商品 ID 查询商品

    参数:
        product_id: 商品 ID

    返回:
        找到则返回商品字典,找不到返回 None
    """
    for p in products:
        if p["id"] == product_id:
            return p
    return None


def get_products_by_category(category):
    """
    根据分类名称获取商品列表

    参数:
        category: 分类名称(如 "手机")

    返回:
        该分类下的所有商品列表
    """
    result = []
    for p in products:
        if p["category"] == category:
            result.append(p)
    return result


def get_new_products():
    """获取所有新品"""
    result = []
    for p in products:
        if p["is_new"]:
            result.append(p)
    return result


def get_products_by_price_range(min_price, max_price):
    """
    按价格区间筛选商品

    参数:
        min_price: 最低价格
        max_price: 最高价格

    返回:
        价格在区间内的商品列表
    """
    result = []
    for p in products:
        if min_price <= p["price"] <= max_price:
            result.append(p)
    return result


# 测试查询函数
print("【商品查询】")
print("-" * 60)

product = get_product_by_id(1)
print(f"ID=1 的商品:{product['name']}(¥{product['price']})")

product = get_product_by_id(999)
print(f"ID=999 的商品:{product}")  # None

phones = get_products_by_category("手机")
print(f"\n手机分类共 {len(phones)} 个商品:")
for p in phones:
    print(f"  - {p['name']}(¥{p['price']})")

new_items = get_new_products()
print(f"\n新品共 {len(new_items)} 个:")
for p in new_items:
    print(f"  - {p['name']}(¥{p['price']})")

cheap = get_products_by_price_range(0, 2000)
print(f"\n¥2000 以下的商品共 {len(cheap)} 个:")
for p in cheap:
    print(f"  - {p['name']}(¥{p['price']})")

print()


# ========================================
# 第三步:商品搜索函数
# ========================================

def search_products(keyword):
    """
    搜索商品(模糊匹配名称和描述)

    参数:
        keyword: 搜索关键词

    返回:
        名称或描述中包含关键词的商品列表
    """
    keyword_lower = keyword.lower()
    results = []
    for p in products:
        name_match = keyword_lower in p["name"].lower()
        desc_match = keyword_lower in p["description"].lower()
        if name_match or desc_match:
            results.append(p)
    return results


def highlight_keyword(text, keyword):
    """
    在文本中高亮关键词(用 【】 包裹)

    参数:
        text: 原始文本
        keyword: 要高亮的关键词

    返回:
        高亮后的文本
    """
    result = text
    keyword_lower = keyword.lower()
    text_lower = text.lower()

    start = text_lower.find(keyword_lower)
    if start != -1:
        end = start + len(keyword)
        result = text[:start] + "【" + text[start:end] + "】" + text[end:]

    return result


# 测试搜索函数
print("【商品搜索】")
print("-" * 60)

search_keyword = "Pro"
results = search_products(search_keyword)
print(f"搜索 '{search_keyword}',找到 {len(results)} 个结果:")
for p in results:
    highlighted_name = highlight_keyword(p["name"], search_keyword)
    print(f"  - {highlighted_name}(¥{p['price']})")

print()

search_keyword = "芯片"
results = search_products(search_keyword)
print(f"搜索 '{search_keyword}',找到 {len(results)} 个结果:")
for p in results:
    print(f"  - {p['name']}{highlight_keyword(p['description'], search_keyword)}")

print()

search_keyword = "不存在的商品xyz"
results = search_products(search_keyword)
print(f"搜索 '{search_keyword}',找到 {len(results)} 个结果")

print()


# ========================================
# 第四步:分页函数
# ========================================

def paginate(data, page=1, page_size=5):
    """
    对数据进行分页

    参数:
        data: 要分页的数据列表
        page: 页码(从 1 开始)
        page_size: 每页数量(默认 5)

    返回:
        分页结果字典,包含总数、页码、每页数量、数据、总页数
    """
    total = len(data)
    total_pages = (total + page_size - 1) // page_size  # 向上取整

    # 页码边界处理
    if page < 1:
        page = 1
    if page > total_pages and total_pages > 0:
        page = total_pages

    start = (page - 1) * page_size
    end = start + page_size

    return {
        "total": total,
        "page": page,
        "page_size": page_size,
        "total_pages": total_pages,
        "items": data[start:end]
    }


def print_pagination(result):
    """美观地打印分页结果"""
    print(f"  总计:{result['total']} 条")
    print(f"  页码:第 {result['page']}/{result['total_pages']} 页")
    print(f"  本页:{len(result['items'])} 条")
    for item in result["items"]:
        print(f"    - {item['name']}(¥{item['price']})")


# 测试分页函数
print("【分页功能】")
print("-" * 60)

print("\n全部商品,第 1 页(每页 5 条):")
page1 = paginate(products, page=1, page_size=5)
print_pagination(page1)

print("\n全部商品,第 2 页:")
page2 = paginate(products, page=2, page_size=5)
print_pagination(page2)

print("\n全部商品,第 3 页:")
page3 = paginate(products, page=3, page_size=5)
print_pagination(page3)

# 分类 + 分页组合
print("\n手机分类,第 1 页(每页 2 条):")
phones = get_products_by_category("手机")
phones_page = paginate(phones, page=1, page_size=2)
print_pagination(phones_page)

# 边界测试:页码超出范围
print("\n页码超出范围测试:")
overflow = paginate(products, page=100, page_size=5)
print(f"  请求第 100 页,实际返回第 {overflow['page']} 页")

print()


# ========================================
# 第五步:用户登录验证函数
# ========================================

def login(username, password):
    """
    验证用户登录

    参数:
        username: 用户名
        password: 密码

    返回:
        登录结果字典,包含 success、message、user
    """
    # 检查用户名和密码是否为空
    if not username:
        return {"success": False, "message": "请输入用户名", "user": None}
    if not password:
        return {"success": False, "message": "请输入密码", "user": None}

    # 查找用户
    for user in users:
        if user["username"] == username:
            if user["password"] == password:
                # 登录成功,返回用户信息(不包含密码)
                safe_user = {
                    "id": user["id"],
                    "username": user["username"],
                    "nickname": user["nickname"],
                    "role": user["role"]
                }
                return {"success": True, "message": "登录成功", "user": safe_user}
            else:
                return {"success": False, "message": "密码错误", "user": None}

    return {"success": False, "message": "用户不存在", "user": None}


# 测试登录函数
print("【用户登录】")
print("-" * 60)

test_cases = [
    ("admin", "admin123", "正确账号密码"),
    ("admin", "wrong", "密码错误"),
    ("nobody", "123456", "用户不存在"),
    ("", "123456", "用户名为空"),
    ("admin", "", "密码为空"),
]

for username, password, desc in test_cases:
    result = login(username, password)
    status = "✅ 通过" if result["success"] else "❌ 失败"
    print(f"  {desc}{status} - {result['message']}")

print()


# ========================================
# 第六步:购物车函数
# ========================================

# 购物车数据(内存中维护,程序结束后清空)
cart = []


def add_to_cart(product_id, quantity=1):
    """
    将商品添加到购物车

    参数:
        product_id: 商品 ID
        quantity: 数量(默认 1)

    返回:
        操作结果字典
    """
    product = get_product_by_id(product_id)
    if product is None:
        return {"success": False, "message": f"商品 ID={product_id} 不存在"}

    if product["stock"] < quantity:
        return {"success": False, "message": f"{product['name']} 库存不足(剩余 {product['stock']})"}

    # 检查购物车中是否已有该商品
    for item in cart:
        if item["product_id"] == product_id:
            item["quantity"] += quantity
            item["subtotal"] = item["price"] * item["quantity"]
            return {"success": True, "message": f"{product['name']} 数量更新为 {item['quantity']}"}

    # 新商品,加入购物车
    cart.append({
        "product_id": product_id,
        "name": product["name"],
        "price": product["price"],
        "quantity": quantity,
        "subtotal": product["price"] * quantity
    })
    return {"success": True, "message": f"{product['name']} 已加入购物车"}


def remove_from_cart(product_id):
    """
    从购物车中移除商品

    参数:
        product_id: 商品 ID

    返回:
        操作结果字典
    """
    for i, item in enumerate(cart):
        if item["product_id"] == product_id:
            removed = cart.pop(i)
            return {"success": True, "message": f"{removed['name']} 已从购物车移除"}
    return {"success": False, "message": f"购物车中没有 ID={product_id} 的商品"}


def update_cart_quantity(product_id, quantity):
    """
    修改购物车中商品的数量

    参数:
        product_id: 商品 ID
        quantity: 新数量(设为 0 则删除)

    返回:
        操作结果字典
    """
    if quantity <= 0:
        return remove_from_cart(product_id)

    for item in cart:
        if item["product_id"] == product_id:
            item["quantity"] = quantity
            item["subtotal"] = item["price"] * quantity
            return {"success": True, "message": f"{item['name']} 数量更新为 {quantity}"}

    return {"success": False, "message": f"购物车中没有 ID={product_id} 的商品"}


def get_cart_summary():
    """
    获取购物车摘要

    返回:
        包含商品列表、总数量、总价格的字典
    """
    total_items = 0
    total_price = 0
    for item in cart:
        total_items += item["quantity"]
        total_price += item["subtotal"]

    return {
        "items": cart,
        "total_items": total_items,
        "total_price": total_price,
        "item_count": len(cart)
    }


def clear_cart():
    """清空购物车"""
    cart.clear()
    return {"success": True, "message": "购物车已清空"}


def print_cart():
    """美观地打印购物车内容"""
    summary = get_cart_summary()
    if summary["item_count"] == 0:
        print("  购物车是空的")
        return

    for item in summary["items"]:
        print(f"  - {item['name']}  ¥{item['price']} × {item['quantity']} = ¥{item['subtotal']}")
    print(f"  {'—' * 40}")
    print(f"  共 {summary['total_items']} 件,合计 ¥{summary['total_price']}")


# 测试购物车函数
print("【购物车功能】")
print("-" * 60)

print("\n1. 添加商品到购物车:")
result = add_to_cart(1, 1)   # iPhone 15 Pro × 1
print(f"  {result['message']}")
result = add_to_cart(5, 2)   # MacBook Pro 14 × 2
print(f"  {result['message']}")
result = add_to_cart(11, 1)  # AirPods Pro 2 × 1
print(f"  {result['message']}")

print("\n2. 当前购物车:")
print_cart()

print("\n3. 再次添加同一商品(数量应该累加):")
result = add_to_cart(1, 2)
print(f"  {result['message']}")

print("\n4. 修改商品数量:")
result = update_cart_quantity(5, 1)
print(f"  {result['message']}")

print("\n5. 删除一个商品:")
result = remove_from_cart(11)
print(f"  {result['message']}")

print("\n6. 最终购物车:")
print_cart()

print("\n7. 测试异常情况:")
result = add_to_cart(999, 1)
print(f"  添加不存在的商品:{result['message']}")

result = add_to_cart(1, 99999)
print(f"  库存不足时添加:{result['message']}")

print()


# ========================================
# 第七步:用列表推导式重写部分函数
# ========================================

print("【列表推导式 vs 普通写法对比】")
print("-" * 60)

# 对比 1:获取所有商品名
# 普通写法
names_normal = []
for p in products:
    names_normal.append(p["name"])

# 列表推导式
names_short = [p["name"] for p in products]

print(f"\n普通写法:{names_normal}")
print(f"列表推导式:{names_short}")
print(f"结果相同:{names_normal == names_short}")

# 对比 2:筛选手机
# 普通写法
phones_normal = []
for p in products:
    if p["category"] == "手机":
        phones_normal.append(p["name"])

# 列表推导式
phones_short = [p["name"] for p in products if p["category"] == "手机"]

print(f"\n手机(普通写法):{phones_normal}")
print(f"手机(列表推导式):{phones_short}")
print(f"结果相同:{phones_normal == phones_short}")

# 对比 3:格式化输出
summaries = [f"{p['name']}{p['price']})" for p in products if p["price"] > 8000]
print(f"\n价格超过 ¥8000 的商品:{summaries}")

print()


# ========================================
# 总结统计
# ========================================
print("=" * 60)
print("本次编写了以下函数:")
print("=" * 60)
functions = [
    ("load_json(filename)", "加载 JSON 数据文件"),
    ("get_product_by_id(product_id)", "根据 ID 查询商品"),
    ("get_products_by_category(category)", "按分类筛选商品"),
    ("get_new_products()", "获取所有新品"),
    ("get_products_by_price_range(min, max)", "按价格区间筛选"),
    ("search_products(keyword)", "模糊搜索商品"),
    ("highlight_keyword(text, keyword)", "关键词高亮"),
    ("paginate(data, page, page_size)", "数据分页"),
    ("print_pagination(result)", "打印分页结果"),
    ("login(username, password)", "用户登录验证"),
    ("add_to_cart(product_id, quantity)", "添加到购物车"),
    ("remove_from_cart(product_id)", "从购物车移除"),
    ("update_cart_quantity(product_id, qty)", "修改购物车数量"),
    ("get_cart_summary()", "获取购物车摘要"),
    ("clear_cart()", "清空购物车"),
    ("print_cart()", "打印购物车"),
]

for func_name, desc in functions:
    print(f"  {func_name:<45} # {desc}")

print(f"\n共 {len(functions)} 个函数,覆盖了商品查询、搜索、分页、用户登录、购物车五大模块。")

运行脚本

python mall_functions.py

完整输出

加载完成:15 个商品,3 个用户,4 个分类
============================================================
【商品查询】
------------------------------------------------------------
ID=1 的商品:iPhone 15 Pro(¥8999)
ID=999 的商品:None

手机分类共 4 个商品:
  - iPhone 15 Pro(¥8999)
  - iPhone 15(¥5999)
  - 华为 Mate 60 Pro(¥6999)
  - 小米 14 Pro(¥4999)

新品共 6 个:
  - iPhone 15 Pro(¥8999)
  - iPhone 15(¥5999)
  - 华为 Mate 60 Pro(¥6999)
  - MacBook Pro 14(¥14999)
  - 华为 MatePad Pro(¥3999)
  - Apple Watch Series 9(¥3299)

¥2000 以下的商品共 3 个:
  - AirPods Pro 2(¥1899)
  - MagSafe 充电器(¥399)
  - USB-C 转接头(¥199)

【商品搜索】
------------------------------------------------------------
搜索 'Pro',找到 5 个结果:
  - iPhone 【Pro】(¥8999)
  - MacBook 【Pro】 14(¥14999)
  - iPad 【Pro】 12.9(¥8999)
  - AirPods 【Pro】 2(¥1899)
  - 华为 MatePad 【Pro】(¥3999)

搜索 '芯片',找到 4 个结果:
  - iPhone 15 Pro:A17 【Pro】 芯片,钛金属设计,48MP 主摄
  - iPhone 15:A16 【芯片】,灵动岛设计,USB-C 接口
  - 华为 Mate 60 Pro:麒麟 9000S,卫星通信,XMAGE 影像
  - MacBook Pro 14:M3 Pro 【芯片】,18 小时续航,Liquid Retina XDR

搜索 '不存在的商品xyz',找到 0 个结果

【分页功能】
------------------------------------------------------------

全部商品,第 1 页(每页 5 条):
  总计:15 条
  页码:第 1/3 页
  本页:5 条
    - iPhone 15 Pro(¥8999)
    - iPhone 15(¥5999)
    - 华为 Mate 60 Pro(¥6999)
    - 小米 14 Pro(¥4999)
    - MacBook Pro 14(¥14999)

全部商品,第 2 页:
  总计:15 条
  页码:第 2/3 页
  本页:5 条
    - ThinkPad X1 Carbon(¥9999)
    - 华为 MateBook X Pro(¥8999)
    - iPad Pro 12.9(¥8999)
    - iPad Air(¥4799)
    - 华为 MatePad Pro(¥3999)

全部商品,第 3 页:
  总计:15 条
  页码:第 3/3 页
  本页:5 条
    - AirPods Pro 2(¥1899)
    - Apple Watch Series 9(¥3299)
    - MagSafe 充电器(¥399)
    - USB-C 转接头(¥199)
    - 笔记本支架(¥299)

手机分类,第 1 页(每页 2 条):
  总计:4 条
  页码:第 1/2 页
  本页:2 条
    - iPhone 15 Pro(¥8999)
    - iPhone 15(¥5999)

页码超出范围测试:
  请求第 100 页,实际返回第 3 页

【用户登录】
------------------------------------------------------------
  正确账号密码:✅ 通过 - 登录成功
  密码错误:❌ 失败 - 密码错误
  用户不存在:❌ 失败 - 用户不存在
  用户名为空:❌ 失败 - 请输入用户名
  密码为空:❌ 失败 - 请输入密码

【购物车功能】
------------------------------------------------------------

1. 添加商品到购物车:
  iPhone 15 Pro 已加入购物车
  MacBook Pro 14 已加入购物车
  AirPods Pro 2 已加入购物车

2. 当前购物车:
  - iPhone 15 Pro  ¥8999 × 1 = ¥8999
  - MacBook Pro 14  ¥14999 × 2 = ¥29998
  - AirPods Pro 2  ¥1899 × 1 = ¥1899
  ————————————————————————————————————————
  共 4 件,合计 ¥40896

3. 再次添加同一商品(数量应该累加):
  iPhone 15 Pro 数量更新为 3

4. 修改商品数量:
  MacBook Pro 14 数量更新为 1

5. 删除一个商品:
  AirPods Pro 2 已从购物车移除

6. 最终购物车:
  - iPhone 15 Pro  ¥8999 × 3 = ¥26997
  - MacBook Pro 14  ¥14999 × 1 = ¥14999
  ————————————————————————————————————————
  共 4 件,合计 ¥41996

7. 测试异常情况:
  添加不存在的商品:商品 ID=999 不存在
  库存不足时添加:iPhone 15 Pro 库存不足(剩余 100)

【列表推导式 vs 普通写法对比】
------------------------------------------------------------

普通写法:['iPhone 15 Pro', 'iPhone 15', '华为 Mate 60 Pro', '小米 14 Pro', 'MacBook Pro 14', 'ThinkPad X1 Carbon', '华为 MateBook X Pro', 'iPad Pro 12.9', 'iPad Air', '华为 MatePad Pro', 'AirPods Pro 2', 'Apple Watch Series 9', 'MagSafe 充电器', 'USB-C 转接头', '笔记本支架']
列表推导式:['iPhone 15 Pro', 'iPhone 15', '华为 Mate 60 Pro', '小米 14 Pro', 'MacBook Pro 14', 'ThinkPad X1 Carbon', '华为 MateBook X Pro', 'iPad Pro 12.9', 'iPad Air', '华为 MatePad Pro', 'AirPods Pro 2', 'Apple Watch Series 9', 'MagSafe 充电器', 'USB-C 转接头', '笔记本支架']
结果相同:True

手机(普通写法):['iPhone 15 Pro', 'iPhone 15', '华为 Mate 60 Pro', '小米 14 Pro']
手机(列表推导式):['iPhone 15 Pro', 'iPhone 15', '华为 Mate 60 Pro', '小米 14 Pro']
结果相同:True

价格超过 ¥8000 的商品:['iPhone 15 Pro(¥8999)', 'MacBook Pro 14(¥14999)', '华为 MateBook X Pro(¥8999)', 'iPad Pro 12.9(¥8999)']

============================================================
本次编写了以下函数:
============================================================
  load_json(filename)                             # 加载 JSON 数据文件
  get_product_by_id(product_id)                   # 根据 ID 查询商品
  get_products_by_category(category)              # 按分类筛选商品
  get_new_products()                              # 获取所有新品
  get_products_by_price_range(min, max)            # 按价格区间筛选
  search_products(keyword)                        # 模糊搜索商品
  highlight_keyword(text, keyword)                # 关键词高亮
  paginate(data, page, page_size)                 # 数据分页
  print_pagination(result)                        # 打印分页结果
  login(username, password)                       # 用户登录验证
  add_to_cart(product_id, quantity)               # 添加到购物车
  remove_from_cart(product_id)                    # 从购物车移除
  update_cart_quantity(product_id, qty)            # 修改购物车数量
  get_cart_summary()                              # 获取购物车摘要
  clear_cart()                                    # 清空购物车
  print_cart()                                    # 打印购物车

共 16 个函数,覆盖了商品查询、搜索、分页、用户登录、购物车五大模块。

六、代码中用到的知识点回顾

mall_functions.py 中,每个 Python 知识点都有对应的实际应用:

知识点在代码中的应用
if/elif/elselogin() 中判断用户名密码是否为空、是否匹配
for 循环get_product_by_id() 中遍历商品列表查找匹配项
while 循环分页的 paginate() 中计算总页数
break搜索到第一个匹配就停止
continue跳过不匹配的商品
range()paginate() 中计算起止位置
enumerate()打印带序号的商品列表
列表推导式筛选手机、获取商品名列表
函数定义全部 16 个函数
参数(默认值)add_to_cart(product_id, quantity=1)
返回值每个函数返回结果字典
字典操作cart.append()cart.pop()
in 关键字keyword in p["name"] 判断是否包含
not / and / or多条件组合判断
f-string格式化输出商品信息
异常边界处理页码超出范围自动修正

七、课后练习

练习 1:添加按评分排序的函数

def get_top_rated_products(top_n=3):
    """
    获取评分最高的 N 个商品

    参数:
        top_n: 返回数量(默认 3)

    返回:
        评分从高到低排序的商品列表
    """
    sorted_products = sorted(products, key=lambda p: p["rating"], reverse=True)
    return sorted_products[:top_n]

top3 = get_top_rated_products(3)
print("评分 Top 3:")
for p in top3:
    print(f"  - {p['name']}{p['rating']} 分)")

提示:sorted() 是 Python 内置的排序函数,key=lambda p: p["rating"] 表示按 rating 字段排序,reverse=True 表示从高到低。

练习 2:添加库存预警函数

def get_low_stock_products(threshold=50):
    """获取库存低于阈值的商品"""
    return [p for p in products if p["stock"] < threshold]

low_stock = get_low_stock_products(60)
print(f"库存低于 60 的商品:{len(low_stock)} 个")
for p in low_stock:
    print(f"  ⚠️ {p['name']} - 仅剩 {p['stock']} 件")

练习 3:添加购物车商品数量统计

def get_cart_category_stats():
    """统计购物车中各分类的商品数量和金额"""
    stats = {}
    for item in cart:
        product = get_product_by_id(item["product_id"])
        cat = product["category"]
        if cat not in stats:
            stats[cat] = {"count": 0, "total": 0}
        stats[cat]["count"] += item["quantity"]
        stats[cat]["total"] += item["subtotal"]
    return stats

八、今日成果总结

今天完成了什么:

  • 学会了 if/elif/else 条件判断
  • 学会了 for/while 循环、break、continue
  • 学会了列表推导式
  • 学会了函数的定义、参数、返回值
  • 编写了 16 个 MallLite 核心业务函数
  • 覆盖了商品查询、搜索、分页、登录、购物车五大模块

当前项目结构:

mall-lite/
├── data/
│   ├── products.json     ← 15 个商品
│   ├── categories.json   ← 4 个分类
│   └── users.json        ← 3 个用户
├── generate_data.py      ← P01:数据生成脚本
├── mall_functions.py     ← P02:核心业务函数(本篇)
├── hello.py
└── venv/

九、下篇预告

P03 - 数据结构与常用操作

下一篇将深入讲解列表、字典、元组、集合的高级操作,以及字符串的更多技巧。然后用这些知识为 MallLite 编写订单管理函数和数据统计模块。P03 的数据结构知识是后续接口自动化中解析 JSON 响应的基础。


系列导航

序号标题状态
P01Python 环境搭建与第一行代码✅ 已发布
P02流程控制与函数✅ 本文
P03数据结构与常用操作下一篇
P04文件操作与异常处理待更新
P05面向对象与模块待更新
P06自动化测试常用技巧待更新
01Web UI 自动化项目总览与环境搭建待更新
02框架基础层搭建待更新
Logo

电商企业物流数字化转型必备!快递鸟 API 接口,72 小时快速完成物流系统集成。全流程实战1V1指导,营造开放的API技术生态圈。

更多推荐