第4章 4.5 综合实战:电商首页 + 商品详情


🎯 开场 3 分钟:为什么要学这个?

上一章我们折腾完了 Vue3 的组合式 API——refreactive、自定义 setup 函数,搞得你手都热了吧?

但光有前端武功还不够,你总得有个「后台」来存储商品、管理订单吧?总不能所有数据都写死在前端代码里。

你有没有遇到过这些情况?

  • 想做一个「购物车」功能,但不知道数据该存在哪里
  • 学了点 Python,但不知道怎么做个「能用」的接口
  • 看了 N 个教程,一运行还是只会 print("Hello World")

这一章,我们用 Python + 简单数据结构,从零搭建一个电商后端雏形:支持查询商品列表、筛选分类、查看商品详情。

学完你就能手撸一个「数据驱动」的小项目,不再是纸上谈兵。


🧱 基础 25 分钟:核心概念

4.5.1 Python 字典:电商数据的「档案袋」

是什么?

如果说列表是一排抽屉(用编号 0、1、2 找东西),那字典就是标\n\nSimple tech illustration expla\n\nAI comic creation scene, creat\n\n签化文件柜——用名字找东西

生活中,字典就像你的手机通讯录:不是「第 3 个联系人是张三」,而是「找张三,打 138xxxx」。

为什么要用?

电商场景里,商品有 id、名称、价格、库存、图片URL……一堆属性。用列表的话,你要记「第 0 位是 id,第 1 位是名称,第 2 位是价格」——累死。

用字典,直接 商品["name"] 拿到名字,代码好读一万倍。

怎么用?

# 定义一个商品字典
product = {
"id": 1001,
"name": "iPhone 15 Pro",
"price": 8999,
"stock": 50,
"category": "手机"
}

# 读取数据
print(product["name"])        # 输出: iPhone 15 Pro
print(product["price"])       # 输出: 8999

# 修改数据
product["stock"] = 49         # 卖了一台
print(product["stock"])       # 输出: 49

字典的 key 必须是不可变类型(字符串、数字、元组),value 可以是任意类型。


4.5.2 字典列表:N 个商品的「商品册」

是什么?

一个字典 = 一件商品的信息。那 N 件商品,就是一个字典的列表(List[Dict])。

就像一个衣柜里有多件衣服,每件衣服有自己的属性卡片。

为什么要用?

真实电商有几百上千个商品,总得有个容器把它们装起来、方便遍历查找吧?

怎么用?

# 商品列表(5 个商品)
products = [
{"id": 1, "name": "iPhone 15", "price": 5999, "category": "手机"},
{"id": 2, "name": "MacBook Pro", "price": 9999, "category": "电脑"},
{"id": 3, "name": "AirPods Pro", "price": 1899, "category": "配件"},
{"id": 4, "name": "iPad Air", "price": 4399, "category": "平板"},
{"id": 5, "name": "小米14", "price": 3999, "category": "手机"},
]

# 遍历所有商品
for p in products:
print(f"{p['name']} - ¥{p['price']}")

4.5.3 函数封装:把「操作」变成「工具」

是什么?

函数就是「封装好的做事步骤」。就像微波炉的「解冻」按钮——你不用管它内部怎么工作,按一下就行。

为什么要用?

如果每次查商品都写一大段代码,项目大了你会疯的。函数让你「写一次,用 N 次」。

怎么用?

# 定义一个函数:按分类筛选商品
def filter_by_category(products, category):
"""
参数:
    products: 商品列表(字典列表)
    category: 要筛选的分类名称
返回:
    符合条件的新列表
"""
result = []
for p in products:
    if p["category"] == category:
        result.append(p)
return result

# 使用函数
phones = filter_by_category(products, "手机")
print(f"手机品类有 {len(phones)} 件商品")
for p in phones:
print(f"  - {p['name']}")

小贴士:函数名用 filter_by_category(下划线分隔)还是 filterByCategory(驼峰)?Python 社区约定用前者,叫 snake_case


4.5.4 列表推导式:一行代码搞定「筛选+转换」

是什么?

列表推导式是 Python 的独门秘籍——用一行代码完成「遍历+筛选+转换」。

想象点菜流水线:服务员喊「所有热菜」,厨房自动过滤出热菜、装盘、上菜。列表推导式就是这个流水线。

为什么要用?

代码短、运行快、Python 面试必问。

怎么用?

# 传统写法(3 行)
expensive = []
for p in products:
if p["price"] > 5000:
    expensive.append(p["name"])

# 列表推导式(1 行搞定)
expensive = [p["name"] for p in products if p["price"] > 5000]
print(expensive)  # ['iPhone 15', 'MacBook Pro', 'iPad Air']

语法格式:[表达式 for item in 可迭代对象 if 条件]


4.5.5 JSON:前后端的「通用语言」

是什么?

JSON 是一种数据格式,Python 字典转成 JSON 后,可以被任何语言(JS、Java、Go…)读取。

就像翻译软件——Python 说「字典」,JSON 翻译成「{key: value}」格式,前端 UniApp 就能用了。

怎么用?

import json

# Python 字典 → JSON 字符串(用于存储/传输)
data = {"name": "iPhone", "price": 5999}
json_str = json.dumps(data, ensure_ascii=False)
print(json_str)  # {"name": "iPhone", "price": 5999}

# JSON 字符串 → Python 字典(用于解析)
back_to_dict = json.loads(json_str)
print(back_to_dict["name"])  # iPhone

ensure_ascii=False 是为了能正确显示中文,否则会显示 Unicode 转义。


🔥 实战 35 分钟:3 个递进小项目

📦 项目 1(5 分钟):商品列表查询

目标:给定商品列表,查询并展示。

import json

# 模拟数据库:电商商品列表
products = [
{"id": 1, "name": "iPhone 15", "price": 5999, "stock": 100, "category": "手机"},
{"id": 2, "name": "MacBook Pro 14", "price": 9999, "stock": 50, "category": "电脑"},
{"id": 3, "name": "AirPods Pro", "price": 1899, "stock": 200, "category": "配件"},
{"id": 4, "name": "iPad Air", "price": 4399, "stock": 80, "category": "平板"},
{"id": 5, "name": "Apple Watch S9", "price": 3299, "stock": 60, "category": "配件"},
{"id": 6, "name": "小米14 Ultra", "price": 5999, "stock": 30, "category": "手机"},
{"id": 7, "name": "华为Mate60", "price": 6999, "stock": 25, "category": "手机"},
{"id": 8, "name": "ThinkPad X1", "price": 8999, "stock": 40, "category": "电脑"},
]

def get_all_products():
"""返回所有商品列表"""
return products

def display_products(product_list):
"""格式化展示商品"""
print("\n" + "=" * 50)
print(f"{'ID':<6}{'商品名称':<20}{'价格':<10}{'库存':<8}{'分类'}")
print("-" * 50)
for p in product_list:
    print(f"{p['id']:<6}{p['name']:<20}¥{p['price']:<8}{p['stock']:<8}{p['category']}")
print("=" * 50)

# 运行
all_products = get_all_products()
display_products(all_products)

预期输出

==================================================
ID    商品名称               价格       库存     分类
--------------------------------------------------
1     iPhone 15              ¥5999     100      手机
2     MacBook Pro 14         ¥9999     50       电脑
3     AirPods Pro            ¥1899     200      配件
4     iPad Air               ¥4399     80       平板
5     Apple Watch S9         ¥3299     60       配件
6     小米14 Ultra           ¥5999     30       手机
7     华为Mate60             ¥6999     25       手机
8     ThinkPad X1            ¥8999     40       电脑
==================================================

一句话:这段代码用字典列表存储商品数据,用函数封装查询逻辑,方便后续复用。


📦 项目 2(15 分钟):分类筛选 + 价格区间

目标:用户可以按「分类」筛选、按「价格区间」过滤,支持多个筛选条件组合。

import json

products = [
{"id": 1, "name": "iPhone 15", "price": 5999, "stock": 100, "category": "手机", "sales": 5200},
{"id": 2, "name": "MacBook Pro 14", "price": 9999, "stock": 50, "category": "电脑", "sales": 1200},
{"id": 3, "name": "AirPods Pro", "price": 1899, "stock": 200, "category": "配件", "sales": 8900},
{"id": 4, "name": "iPad Air", "price": 4399, "stock": 80, "category": "平板", "sales": 3400},
{"id": 5, "name": "Apple Watch S9", "price": 3299, "stock": 60, "category": "配件", "sales": 4500},
{"id": 6, "name": "小米14 Ultra", "price": 5999, "stock": 30, "category": "手机", "sales": 2800},
{"id": 7, "name": "华为Mate60", "price": 6999, "stock": 25, "category": "手机", "sales": 3100},
{"id": 8, "name": "ThinkPad X1", "price": 8999, "stock": 40, "category": "电脑", "sales": 980},
]

def filter_products(products, category=None, min_price=None, max_price=None):
"""
多条件筛选商品

参数:
    category: 分类名称(可选)
    min_price: 最低价格(可选)
    max_price: 最高价格(可选)
"""
result = products

# 分类筛选
if category:
    result = [p for p in result if p["category"] == category]

# 最低价筛选
if min_price is not None:
    result = [p for p in result if p["price"] >= min_price]

# 最高价筛选
if max_price is not None:
    result = [p for p in result if p["price"] <= max_price]

return result

def sort_products(products, sort_by="sales", reverse=True):
"""
按指定字段排序商品

参数:
    sort_by: 排序字段(sales/price/stock)
    reverse: True 为降序,False 为升序
"""
return sorted(products, key=lambda x: x[sort_by], reverse=reverse)

# ========== 演示 ==========

print("【场景1】查看所有手机")
phones = filter_products(products, category="手机")
for p in phones:
print(f"  {p['name']} ¥{p['price']}")

print("\n【场景2】查看 3000-6000 元的商品")
mid_range = filter_products(products, min_price=3000, max_price=6000)
for p in mid_range:
print(f"  {p['name']} ¥{p['price']}")

print("\n【场景3】按销量排序(前3名)")
top_sales = sort_products(products, sort_by="sales", reverse=True)[:3]
for i, p in enumerate(top_sales, 1):
print(f"  第{i}名: {p['name']} 销量={p['sales']}")

# 导出为 JSON(模拟接口返回)
json_output = json.dumps(mid_range, ensure_ascii=False, indent=2)
print("\n【JSON 输出示例】")
print(json_output)

预期输出

【场景1】查看所有手机
iPhone 15 ¥5999
小米14 Ultra ¥5999
华为Mate60 ¥6999

【场景2】查看 3000-6000 元的商品
iPhone 15 ¥5999
iPad Air ¥4399
Apple Watch S9 ¥3299
小米14 Ultra ¥5999

【场景3】按销量排序(前3名)
第1名: AirPods Pro 销量=8900
第2名: iPhone 15 销量=5200
第3名: Apple Watch S9 销量=4500

【JSON 输出示例】
[
{
"id": 1,
"name": "iPhone 15",
"price": 5999,
...
}
]

一句话:函数参数设为 None(而不是直接不传)是为了区分「没传」和「传了个空」,这样多个筛选条件可以随意组合。


📦 项目 3(15 分钟):购物车 + 订单模拟

目标:做一个简易购物车,支持添加商品、计算总价、生成订单。

import json
from datetime import datetime

products = [
{"id": 1, "name": "iPhone 15", "price": 5999, "stock": 100, "category": "手机"},
{"id": 2, "name": "MacBook Pro 14", "price": 9999, "stock": 50, "category": "电脑"},
{"id": 3, "name": "AirPods Pro", "price": 1899, "stock": 200, "category": "配件"},
]

class ShoppingCart:
"""购物车类"""

def __init__(self):
    self.items = []  # 购物车里的商品

def add_item(self, product_id, quantity=1):
    """添加商品到购物车"""
    # 查找商品
    product = next((p for p in products if p["id"] == product_id), None)
    if not product:
        print(f"❌ 商品ID {product_id} 不存在")
        return False

    # 检查库存
    if product["stock"] < quantity:
        print(f"❌ {product['name']} 库存不足(剩余 {product['stock']})")
        return False

    # 检查购物车是否已有该商品
    existing = next((item for item in self.items if item["product"]["id"] == product_id), None)
    if existing:
        existing["quantity"] += quantity
    else:
        self.items.append({
            "product": product,
            "quantity": quantity
        })

    print(f"✅ 已添加 {product['name']} x{quantity} 到购物车")
    return True

def remove_item(self, product_id):
    """从购物车移除商品"""
    self.items = [item for item in self.items if item["product"]["id"] != product_id]
    print(f"🗑️ 已从购物车移除商品ID {product_id}")

def get_total(self):
    """计算总金额"""
    return sum(item["product"]["price"] * item["quantity"] for item in self.items)

def view_cart(self):
    """查看购物车内容"""
    if not self.items:
        print("🛒 购物车是空的")
        return

    print("\n" + "=" * 50)
    print("🛒 购物车内容")
    print("-" * 50)
    for item in self.items:
        p = item["product"]
        subtotal = p["price"] * item["quantity"]
        print(f"{p['name']:<20} x{item['quantity']} = ¥{subtotal}")
    print("-" * 50)
    print(f"{'总计':<20} ¥{self.get_total()}")
    print("=" * 50)

def checkout(self):
    """结算:生成订单"""
    if not self.items:
        print("❌ 购物车是空的,无法结算")
        return None

    # 生成订单
    order = {
        "order_id": f"ORD{datetime.now().strftime('%Y%m%d%H%M%S')}",
        "created_at": datetime.now().isoformat(),
        "items": self.items.copy(),
        "total": self.get_total(),
        "status": "已支付"
    }

    # 更新库存
    for item in self.items:
        p = item["product"]
        p["stock"] -= item["quantity"]

    # 清空购物车
    self.items = []

    print(f"✅ 订单生成成功!订单号:{order['order_id']}")
    print(f"💰 实付金额:¥{order['total']}")
    return order

# ========== 演示 ==========
cart = ShoppingCart()

print("【第1步】添加商品到购物车")
cart.add_item(1, 1)   # iPhone 15
cart.add_item(3, 2)   # AirPods Pro x2
cart.add_item(2, 1)   # MacBook Pro 14

print("\n【第2步】查看购物车")
cart.view_cart()

print("\n【第3步】再添加一台 iPhone 15(购物车里已有一个,再加一个)")
cart.add_item(1, 1)

print("\n【第4步】再次查看购物车")
cart.view_cart()

print("\n【第5步】结算!")
order = cart.checkout()
if order:
print(f"\n📦 订单详情:")
print(json.dumps(order, ensure_ascii=False, indent=2))

预期输出

【第1步】添加商品到购物车
✅ 已添加 iPhone 15 x1 到购物车
✅ 已添加 AirPods Pro x2 到购物车
✅ 已添加 MacBook Pro 14 x1 到购物车

【第2步】查看购物车
==================================================
🛒 购物车内容
--------------------------------------------------
iPhone 15            x1 = ¥5999
AirPods Pro          x2 = ¥3798
MacBook Pro 14       x1 = ¥9999
--------------------------------------------------
总计                 ¥19796
==================================================

【第3步】再添加一台 iPhone 15(购物车里已有一个,再加一个)
✅ 已添加 iPhone 15 x1 到购物车

【第4步】再次查看购物车
==================================================
🛒 购物车内容
--------------------------------------------------
iPhone 15            x1 = ¥5999
AirPods Pro          x2 = ¥3798
MacBook Pro 14       x1 = ¥9999
iPhone 15            x1 = ¥5999
--------------------------------------------------
总计                 ¥19796   ← 等等,这里有问题!数量没累加
==================================================

【第5步】结算!
✅ 订单生成成功!订单号:ORD20250626143025
💰 实付金额:¥19796

📦 订单详情:
{
"order_id": "ORD20250626143025",
"created_at": "2026-06-26T14:30:25.xxx",
"items": [...],
"total": 19796,
"status": "已支付"
}

⚠️ 这里暴露了一个问题:同个商品被重复添加成了两条记录。进阶练习里会让你修复这个 bug。


💪 进阶 20 分钟:常见坑 + 性能小贴士

❌ 坑 1:可变默认参数

# ❌ 错误写法
def add_item(items=[]):  # 默认参数是列表,这是可变对象!
items.append("新商品")
return items

# 调用两次
print(add_item())  # ['新商品']
print(add_item())  # ['新商品', '新商品'] ← 累积了!

# ✅ 正确写法
def add_item(items=None):
if items is None:
    items = []
items.append("新商品")
return items

说白了:默认参数只在函数定义时创建一次。如果它是可变对象,后续调用会共享同一个对象。


❌ 坑 2:字典 key 不存在

product = {"name": "iPhone", "price": 5999}

# ❌ 错误:key 不存在会报错
# print(product["stock"])  # KeyError: 'stock'

# ✅ 正确:用 get() 方法,不存在返回默认值
print(product.get("stock", 0))  # 0
print(product.get("name"))       # iPhone(存在,正常返回)

❌ 坑 3:循环修改列表

nums = [1, 2, 3, 4, 5]

# ❌ 错误:边遍历边删除,可能漏元素
for n in nums:
if n % 2 == 0:
    nums.remove(n)  # 危险!

# ✅ 正确:创建新列表
nums = [n for n in nums if n % 2 != 0]
print(nums)  # [1, 3, 5]

❌ 坑 4:==is 混淆

a = [1, 2, 3]
b = [1, 2, 3]

print(a == b)   # True  ← 值相等
print(a is b)   # False ← 不是同一个对象

c = a
print(a is c)   # True  ← 同一个对象

记忆口诀:== 问「值相等吗」,is 问「是同一个人吗」。


❌ 坑 5:列表推导式副作用

# ❌ 错误:列表推导式里有副作用
results = [y := x * 2, x for x in range(5)]  # 尽量别用 walrus operator

# ✅ 正确:保持简洁,分步写
doubled = [x * 2 for x in range(5)]

⚡ 性能小贴士:大量数据用生成器

import sys

# 列表:一次性和全部装进内存
big_list = [x ** 2 for x in range(100000)]
print(f"列表占用:{sys.getsizeof(big_list)} bytes")

# 生成器:按需产生,用多少占多少
big_gen = (x ** 2 for x in range(100000))
print(f"生成器占用:{sys.getsizeof(big_gen)} bytes")

生成器就像「自来水厂」——你打开水龙头才来水,不用提前建一个大水库。


🔍 调试技巧:print 大法

def buggy_function(data):
print(f"📥 入参:{data}")          # 入口打印
result = data * 2
print(f"📤 结果:{result}")       # 出口打印
return result

buggy_function(5)
# 📥 入参:5
# 📤 结果:10

简单场景用 print,复杂项目用 logging 模块(可以控制输出级别)。


✏️ 练习题 + 作业题

练习 1(1 分钟):抄改变量

# 原始代码:筛选手机
phones = [p for p in products if p["category"] == "手机"]

# 练习:筛选"电脑"分类
# 预期输出:MacBook Pro 14, ThinkPad X1

练习 2(2 分钟):加个判断

products = [{"name": "iPhone", "price": 5999}, {"name": "AirPods", "price": 1899}]

# 原始:打印所有商品
for p in products:
print(p["name"])

# 练习:只打印价格 > 3000 的商品
# 预期输出:iPhone

练习 3(2 分钟):新数据处理

# 练习:用列表推导式,从下面这个销售数据中找出「季度销售额 > 100万」的月份
sales_data = [
{"month": "1月", "sales": 80},
{"month": "2月", "sales": 120},
{"month": "3月", "sales": 95},
{"month": "4月", "sales": 150},
]

# 提示:sales_data 是一个字典列表,sales 是销售额字段
# 预期输出:[{"month": "2月", "sales": 120}, {"month": "4月", "sales": 150}]

练习 4(3 分钟):组合两个函数

# 项目 2 有 filter_products 和 sort_products
# 练习:先筛选「配件」分类,再按价格升序排列

categories = [
{"name": "AirPods", "price": 1899, "category": "配件"},
{"name": "Watch", "price": 3299, "category": "配件"},
{"name": "手机壳", "price": 99, "category": "配件"},
]

# 提示:先 filter 再 sort(链式调用)
# 预期输出:手机壳(99) → AirPods(1899) → Watch(3299)

练习 5(2 分钟):Debug 分析

# 用户运行这段代码报错,请分析原因
cart = ShoppingCart()
cart.add_item(1, 50)  # 报错:库存不足
print(cart.items)      # 想看购物车内容

# 报错信息:❌ iPhone 15 库存不足(剩余 100)
# 问题:用户买了 50 台,为什么报库存不足?

# 提示:检查库存判断逻辑是否有问题

📝 作业:做一个「商品收藏夹」小工具

需求描述
做一个命令行工具,模拟用户收藏商品、查看收藏夹、计算收藏商品总价值。

功能点
1. 添加商品到收藏夹(根据商品ID)
2. 查看收藏夹所有商品
3. 计算收藏夹商品总价
4. 移除收藏夹中的商品
5. 支持从 JSON 文件保存/加载收藏夹

加分项
1. 支持按价格排序显示收藏夹
2. 添加「猜你喜欢」功能:根据已收藏商品的分类,推荐同分类其他商品

验收标准
- 能运行不报错
- 输出格式清晰
- 代码有适当注释
- 用到了本章至少 3 个核心知识点(字典、列表推导式、函数、JSON)

提交方式:评论区贴代码,或打包成 .py 文件下载链接


📚 总结 + 资源

本文学了 3 个核心点
- ✅ 字典和字典列表:电商数据的「档案袋」和「商品册」
- ✅ 函数封装 + 列表推导式:让代码复用、简洁、高效
- ✅ JSON 序列化:Python 和前端沟通的「通用语言」

延伸资源

资源 链接 适合谁
Python 官方文档 · 字典 docs.python.org/3/tutorial/datastructures.html#dictionaries 查漏补缺
《Python 编程:从入门到实践》 人民邮电出版社 系统学习
知乎 · Python 入门教程(最通俗) zhihu.com 入门扫盲

互动钩子

🎯 你在写爬虫或数据处理时,是怎么组织商品数据的?用过哪些奇怪的数据结构?

评论区聊聊,老粉优先回复!

下一章我们要进入「微信小程序原生能力」——学了这么久 Python,是时候让你的 UniApp 项目真正跑在小程序上了。敬请期待!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。