当前位置: 首页 > news >正文

Python 语法练习不能只停留在基础语法:从库存扣减业务理解代码逻辑

很多人在学习 Python 时,包括我自己最开始也是,一直停留在变量、判断、循环、字典、函数这些基础语法的练习上。语法本身并不难,真正难的是:如何把一个真实业务场景,拆解成程序可以执行的代码逻辑

所以这类练习不能只是写几个ifforwhile,而应该从业务流程出发,先理解业务规则,再把规则转换成代码判断、数据结构和执行流程。

整体训练路径如下:

业务规则理解 ↓ 命令行脚本实现 ↓ 函数封装 ↓ 接口化改造 ↓ 前端页面调用接口 ↓ 接口文档整理

本文先完成前两个阶段:业务规则拆解 + 命令行脚本实现

以下是 我让GPT帮我生成的Python 基础语法训练的练习题,不仅可以练习python的语法还能够加深自己对于业务场景的理解,还能够深入的了解到前后端是如何进行联通的。

一、业务需求原题

库存扣减系统业务背景

假设某系统中有商品库存:

products = { "P001": {"name": "鼠标", "stock": 10, "price": 50}, "P002": {"name": "键盘", "stock": 5, "price": 120}, "P003": {"name": "显示器", "stock": 3, "price": 899} }

用户下单规则:

  1. 商品编号必须存在
  2. 购买数量必须大于 0
  3. 购买数量不能超过库存
  4. 下单成功后扣减库存
  5. 下单失败不能扣减库存

题目 1:单商品下单

用户输入:

商品编号 购买数量

程序判断是否可以下单。

下单成功输出:

下单成功 商品名称 购买数量 订单金额 剩余库存

下单失败输出具体原因。


题目 2:多商品购物车下单

用户可以连续输入多个商品和数量。

要求:

  1. 输入q结束添加商品
  2. 商品不存在时提示错误
  3. 库存不足时提示错误
  4. 成功添加到购物车后,先不扣库存
  5. 用户确认下单后,再统一扣减库存
  6. 输出订单总金额

题目 3:库存预占逻辑

在多商品购物车基础上,增加“库存预占”。

规则:

  1. 添加商品到购物车成功后,库存进入预占状态
  2. 预占库存不允许被其他订单使用
  3. 用户取消订单时,释放预占库存
  4. 用户确认订单时,预占库存正式扣减

你需要设计两个字段:

stock locked_stock

要求实现:

  1. 查询可售库存
  2. 添加购物车时增加 locked_stock
  3. 取消订单时减少 locked_stock
  4. 确认订单时减少 stock,同时减少 locked_stock

二、原题业务逻辑拆解

2.1 题目一:单商品下单

用户进行单个商品下单时,首先需要对用户输入的信息先进行用户使用规则的判断,然后再进行后续的业务逻辑处理,可以将其分为校验阶段和执行阶段:
以下是校验阶段。

[开始] ↓ 1. 检查商品是否存在? (不存在 -> 报错退出) ↓ 2. 检查数量是否大于0? (不大于 -> 报错退出) ↓ 3. 检查库存是否足够? (不够 -> 报错退出) ↓ 4. 校验通过:计算金额、扣减库存 ↓ 5. 输出成功账单 [结束]

校验完成之后,再进入到后续的库存处理和订单金额的计算处理。

在这道题目中主要包含两个变量的计算。

  • 计算金额:单价* 数量。

  • 扣减库存:更新字典中的旧库存

那么转化为代码实现之前,我们需要将其转化为代码思想

用户输入数据后,会先校验输入的商品编号是否存在,以及所需商品是否有足够的库存。 商品编号存在且商品有足够的库存量,才会去执行后续的减少库存、计算金额等操作,否则就应该让用户重新输入商品信息。
简单来说就是:
输入数据 --> 合法性校验 --> 业务规则判断 --> 修改业务数据 --> 返回处理结果
实际的代码实现,我们会使用到if...elif...else 来展现我们的业务逻辑,如下:

products = { "P001": {"name": "鼠标", "stock": 10, "price": 50}, "P002": {"name": "键盘", "stock": 5, "price": 120}, "P003": {"name": "显示器", "stock": 3, "price": 899} } # 模拟用户输入(你可以换成 input() 获取) prod_id = "P001" quantity = 3 # === 业务逻辑转化:开始校验 === # 1. 校验商品是否存在 if prod_id not in products: print(f"下单失败:商品编号 {prod_id} 不存在!") # 2. 校验购买数量是否大于 0 elif quantity <= 0: print("下单失败:购买数量必须大于 0!") # 3. 校验库存是否足够 elif quantity > products[prod_id]["stock"]: current_stock = products[prod_id]["stock"] print(f"下单失败:库存不足!当前商品剩余库存为 {current_stock}") # === 校验全部通过,执行下单 === else: # 获取商品信息 product_info = products[prod_id] # 4. 计算金额与扣减库存 order_amount = product_info["price"] * quantity product_info["stock"] -= quantity # 修改原字典中的库存 # 5. 下单成功输出 print(" 下单成功 !") print(f"商品名称:{product_info['name']}") print(f"购买数量:{quantity}") print(f"订单金额:{order_amount} 元") print(f"剩余库存:{product_info['stock']}")

2.2 题目二 :多商品购物车下单

题目二在题目一的基础上增加了购物车逻辑。用户可以连续输入多个商品和数量,规则如下:

  1. 输入q结束添加商品
  2. 商品不存在时提示错误
  3. 库存不足时提示错误
  4. 成功添加到购物车后,先不扣库存
  5. 用户确认下单后,再统一扣减库存
  6. 输出订单总金额

对于这一题来说,我们可以把这个业务想象成去超市推着购物车购物:

  1. 加车阶段:你在货架前挑选商品,往购物车里放。(此时你只是把东西放进车里,超市货架上的商品并没有真正变少,但你需要边拿边看货架上还有没有,所以会考虑库存的问题。)

  2. 结算阶段:你推着购物车去收银台。收银员帮你计算总价。

  3. 扣减阶段:你付了钱(也就是确认下单),超市后台库存系统才真正把这些商品数量减掉。

要实现这个复杂的流程,我们需要解决两个核心问题:

  • 怎么代表“购物车”?—— 用一个新字典cart = {},结构为{"商品编号": 购买数量}

  • 怎么在加车时预防“库存为负”?—— 如果用户第一次加了2个鼠标,第二次又加了9个(总共11个,但库存只有10个),此时必须能识别出库存不足,不然库存信息就会出现负数的情况,这显然是不符合实际情况的。

业务逻辑梳理清楚之后,那么我们进一步进行对应的代码逻辑的映射处理:

核心转化对照表
业务规则业务描述对应的 Python 代码逻辑
规则 1输入q结束添加商品使用while True循环,并在输入为'q'时执行break退出循环。
规则 2商品不存在时提示错误

if prod_id not in products: 提示用户输出错误,并继续进行循环

规则 3库存不足时提示错误

不能只看原始库存,要看原始库存 - 购物车里已有的数量

in_cart_num = cart.get(prod_id, 0)

if quantity > (products[prod_id]["stock"] - in_cart_num):

规则 4成功加车,不扣库存

不修改products,而是修改购物车字典:

cart[prod_id] = cart.get(prod_id, 0) + quantity

规则 5确认下单后,统一扣减循环结束后,用一个for循环遍历cart,批量修改products里的库存并累加总价。

我们针对已有的规则进行了代码逻辑的梳理。
那么现在在题1的基础上撰写题目2 的代码:

# 原始商品数据 products = { "P001": {"name": "鼠标", "stock": 10, "price": 50}, "P002": {"name": "键盘", "stock": 5, "price": 120}, "P003": {"name": "显示器", "stock": 3, "price": 899} } # 初始化一个空的购物车 结构:{"P001": 数量, "P002": 数量} cart = {} print("=== 阶段一:选购商品(暂不扣库存) ===") while True: prod_id = input("\n请输入商品编号(输入 q 结算退出): ").strip() if prod_id.lower() == 'q': break # 1. 校验商品是否存在 if prod_id not in products: print(" 错误:商品编号不存在,请重新输入!") continue # 跳过本次循环,让用户重新输入 try: quantity = int(input(f"请输入购买 [{products[prod_id]['name']}] 的数量: ")) if quantity <= 0: print(" 错误:购买数量必须大于 0!") continue except ValueError: print(" 错误:请输入合法的数字!") continue # 2. 核心校验:校验库存(必须减去购物车里已经占用的数量) already_in_cart = cart.get(prod_id, 0) # 看看购物车里之前放了多少个 available_stock = products[prod_id]["stock"] - already_in_cart # 实际还能拿多少个 if quantity > available_stock: print(f" 错误:库存不足!该商品剩余可用库存为 {available_stock} 个(您购物车已有 {already_in_cart} 个)。") continue # 3. 满足条件,加入购物车 cart[prod_id] = already_in_cart + quantity print(f"🛒 已成功将 {quantity} 个 [{products[prod_id]['name']}] 放入购物车。") # === 阶段二:统一结算与扣减库存 === if not cart: print("\n购物车为空,交易结束。") else: print("\n=== 阶段二:确认下单与结算 ===") print("您的购物车清单如下:") for pid, num in cart.items(): print(f"- {products[pid]['name']} x {num}") confirm = input("\n是否确认下单?(y/n): ").strip().lower() if confirm == 'y': total_order_amount = 0 # 订单总金额 # 统一扣库存和算总价 for pid, num in cart.items(): # 计算单项商品总价并累加 item_price = products[pid]["price"] * num total_order_amount += item_price # 统一扣减真实库存 products[pid]["stock"] -= num print("\n 下单成功! ") print(f"订单总金额为:{total_order_amount} 元") print("\n最新库存状态一览:") for pid, info in products.items(): print(f"商品: {info['name']} | 剩余库存: {info['stock']}") else: print("\n 订单已取消,库存未发生变化。")

2.3 题目三:库存预占逻辑

在真实电商系统中,仅仅使用购物车还不够。

因为可能出现多个用户同时购买同一个商品的情况。例如:

商品 P001 库存只有 10 个 用户 A 加入购物车 8 个 用户 B 也加入购物车 5 个

如果系统不做限制,就可能出现超卖。

所以题目三是在题二上增加了一个业务问题:会进一步引入“库存预占”逻辑(商品加入购物车后,虽然还没有正式下单,但这部分库存应该先锁住。),那么可以增加一个字段:

products = { "P001": {"name": "鼠标", "stock": 10, "locked_stock": 0, "price": 50} } # stock:真实库存 # locked_stock:已被购物车或订单预占的库存

可售库存应该这样计算:

#可售库存 = stock - locked_stock available_stock = product["stock"] - product["locked_stock"]

本题需要实现的业务逻辑,可以拆分为以下所示:

""" 1. 商品数据里加 locked_stock 2. 输入商品编号 3. 判断商品是否存在 4. 输入购买数量 5. 判断数量是否合法 6. 计算可售库存 stock - locked_stock 7. 判断可售库存是否足够 8. 足够的话,加入购物车 9. 同时增加 locked_stock 10. 用户输入 q 后进入结算 11. 遍历购物车,计算金额 12. 正式扣减 stock 13. 释放 locked_stock 14. 输出订单总金额和库存状态 """

题目三的核心业务规则是:

""" 1、添加购物车成功 → 增加 locked_stock 2、取消订单 → 减少 locked_stock 3、确认订单 → 减少 stock,同时减少 locked_stock """ product["locked_stock"] += count #加入购物车 # ----------确认订单 ------------ products[pid]["stock"] -= item["count"] #减少商品库存 products[pid]["locked_stock"] -= item["count"] # 释放预占库存

这个题三的业务规则其实已经很接近现在真实电商系统中的库存处理思想。

代码输出:

按照梳理好的业务逻辑,在进行代码的撰写会简单很多,最后实现本题的代码如下:

products = { "P001": {"name": "鼠标", "stock": 10, "price": 50, "locked_stock": 0}, "P002": {"name": "键盘", "stock": 5, "price": 120, "locked_stock": 0}, "P003": {"name": "显示器", "stock": 3, "price": 899, "locked_stock": 0} } def inventory(): Shopping_cart = [] while True: use90 = input("请输入你所需的商品编号,输入 q 结束添加:").strip().upper() if use90 == "Q": print("商品添加结束,准备进入最终结算!") break if use90 not in products: print("您所输入的商品编号不存在,请您重新输入!") continue product = products[use90] use00 = input("请输入您所想要的商品数量,输入 q 退出:").strip() if use00.upper() == "Q": print("商品添加结束,准备进入最终结算!") break try: use = int(use00) except ValueError: print("请输入正确的数字,或者输入 q 退出!") continue if use <= 0: print("商品的数量不能小于或等于 0") continue # 可售库存 = 总库存 - 已预占库存 available_stock = product["stock"] - product["locked_stock"] if use > available_stock: print(f"库存不足,当前可售库存为 {available_stock} 件。") continue product["locked_stock"] += use cart_item = { "pid": use90, "name": product["name"], "count": use, "price": product["price"] } Shopping_cart.append(cart_item) print(f"成功将 {use} 件商品【{product['name']}】加入购物车!") print(f"当前商品总库存:{product['stock']},已预占库存:{product['locked_stock']},可售库存:{product['stock'] - product['locked_stock']}") if not Shopping_cart: print("您的购物车空空如也,欢迎下次光临!") return print("\n" + "=" * 15 + " 最终订单结算 " + "=" * 15) total_order_price = 0 for item in Shopping_cart: item_total = item["count"] * item["price"] total_order_price += item_total pid = item["pid"] # 确认订单时,正式扣减总库存 products[pid]["stock"] -= item["count"] # 确认订单后,预占库存要减少,不是增加 # 原因:之前加入购物车时已经 locked_stock += count # 现在订单确认了,这部分库存从“预占”变成“正式扣减”,所以 locked_stock 要释放掉 products[pid]["locked_stock"] -= item["count"] print(f"您所需的商品【{item['name']}】,数量为 {item['count']},订单金额为 {item_total} 元") print( f"商品【{products[pid]['name']}】结算后," f"剩余库存:{products[pid]['stock']}," f"预占库存:{products[pid]['locked_stock']}" ) print(f"\n你的订单总价为 {total_order_price} 元") print("\n" + "=" * 15 + " 当前库存情况 " + "=" * 15) for pid, product in products.items(): available_stock = product["stock"] - product["locked_stock"] print( f"{pid}:{product['name']}," f"总库存:{product['stock']}," f"预占库存:{product['locked_stock']}," f"可售库存:{available_stock}" ) inventory()
题二和题三的关系:

题二是题三的基础版,题三是题二的增强版。

""" #题二业务逻辑: 商品校验 数量校验 库存校验 添加购物车 最后扣库存 #题三业务逻辑: 商品校验 数量校验 可售库存校验 添加购物车 增加 locked_stock 确认订单后 stock -= count 确认订单后 locked_stock -= count """

三、从命令行脚本到接口化代码的演进方向

当我们在学习时会把所有逻辑都写在一个while循环或者一个很长的代码块里,程序虽然能运行,但随着功能增加,这些判断会不断增加,最终形成几百行甚至上千行代码。

后续阅读代码的人需要从头看到尾才能理解程序逻辑,代码会越来越难维护。后续也逐渐形成了
标准的业务开发四步

第一步:后端写业务逻辑
第二步:后端包装成接口(使用框架将业务代码包装,并暴露相应的接口地址)
第三步:前端设计组件
第四步:前后端联调对接

下文中我们讨论的则是将我们所撰写的业务逻辑代码,将其包装为前端JS进行请求后所响应的后端接口代码。因此,下一步最重要的事情并不是立刻学习框架,而是先学会如何拆分代码结构,将不同职责的代码拆分成独立函数,每一个函数只负责一件事情。

3.1 接口化代码的基础分层

为了让代码更清晰,我们按照三层结构来拆:

接口层 Controller / API ↓ 业务层 Service ↓ 数据层 Repository

在库存系统中,这三层可以这样理解:

层级负责内容在库存系统中的例子
接口层接收前端请求,返回 JSON 响应/api/cart/items/api/orders/confirm
业务层处理业务规则和业务流程添加购物车、预占库存、确认下单、取消订单
数据层查询和修改数据查询商品、修改库存、保存购物车

我们暂时不接真实数据库,而是继续用字典模拟数据,同样可以实现我们的练习。
3.2 从命令行中拆分代码

命令行脚本中,通常会把输入、判断、计算、输出都写在一起。

例如添加购物车时,命令行写法可以是:

product_id = input("请输入商品编号:") quantity = int(input("请输入购买数量:")) if product_id not in products: print("商品不存在") elif quantity <= 0: print("数量必须大于 0") else: products[product_id]["locked_stock"] += quantity cart[product_id] = cart.get(product_id, 0) + quantity print("添加购物车成功")

接口化之后,这段逻辑被拆成了三部分。

第一部分:前端输入不再由后端input()获取

命令行里是:

product_id = input("请输入商品编号:") quantity = int(input("请输入购买数量:"))

接口化以后,前端会通过请求体 body 发送 JSON:

{ "product_id": "P001", "quantity": 2 }

然后前端所发出的请求,在后端通过请求模型接收:

class CartItemRequest(BaseModel): product_id: str quantity: int

接口函数中直接拿到,然后再去执行其中的业务函数,并返回处理值。

def add_to_cart_api(request: CartItemRequest): product_id = request.product_id quantity = request.quantity

也就是说:

命令行输入 input()变成了前端 JSON 请求体 + 后端请求参数,然后变为了后端业务代码运行的数据源。


第二部分:业务判断放到 Service 层

原来写在主流程里的判断:

if product_id not in products: print("商品不存在") if quantity <= 0: print("数量必须大于 0") if quantity > available_stock: print("库存不足")

现在放到了业务函数中:

def add_to_cart_service(product_id: str, quantity: int): product_id = product_id.strip().upper() product = find_product_by_id(product_id) if product is None: return False, f"商品编号 {product_id} 不存在", None if quantity <= 0: return False, "购买数量必须大于 0", None available_stock = calculate_available_stock(product_id) if quantity > available_stock: return False, f"库存不足,当前可售库存为 {available_stock}", None increase_locked_stock(product_id, quantity) add_cart_item(product_id, quantity) return True, "添加购物车成功", { "cart": get_cart_summary_service(), "products": get_product_list_service() }

这样做的好处是:业务函数不关心它是被命令行调用,还是被接口调用。

它只关心一件事:

给我 product_id 和 quantity ,我来判断能不能添加购物车。如果可以,就修改库存和购物车状态
最后返回处理结果。这样很纯粹,后续涉及相同的业务逻辑,就可以直接调用该函数,不需要再次撰写这段相同代码,从而降低了代码的耦合度、提升了代码的复用性。


第三部分:输出不再使用print(),而是返回 JSON

命令行里是:

print("添加购物车成功")

接口化以后是:

return api_response(success, message, data)

统一返回JSON 数据给前端:

{ "success": true, "message": "添加购物车成功", "data": { "cart": {}, "products": [] } }

前端拿到这个 JSON 后,就可以展示提示信息、刷新商品列表、刷新购物车。

剩下的其他命令行脚本,代码也可以按照这种方式进行拆解,快动手试试吧!

四、前置知识

实际上我们在将命令行式代码转化为接口化代码之前,我认为有些必须要了解的知识内容。如下

4.1 常见前端文件及其各自作用:

所以要明确前端文件中主要分为三类,HTML、CSS、JS,来看看它们各自的作用:

类别作用
HTML负责将整个页面的整体布局
CSS前端页面样式
JS页面组件元素的交互设计,提交请求、接收后端返回结果。

但由于 JS 是在浏览器中运行的,python是在服务器中运行的,二者不在同一个运行环境中。
因此JS需要请求后端暴露出来的接口,然后请求以JSON格式方式传递给后端。


4.2 JS与python后端代码中的接口交互。

fetch("/api/cart/items", { //向后端该接口地址发送POST请求 method: "POST", //请求方式 headers: { //请求头,说明请求内容的格式 "Content-Type": "application/json" }, body: JSON.stringify({ product_id: "P001", quantity: 2 }) }) //将请求头 和请求体都放置在JSON中进行发送后端接口。

然后后端接口中接受这个请求:

@app.post("/api/cart/items") #监听并处理发送到该路径的 POST 请求 def api_add_to_cart(): # 执行这个后端函数 data = request.get_json() #先解析JSON格式中的数据 product_id = data.get("product_id") quantity = int(data.get("quantity")) success, message, result = add_to_cart(product_id, quantity) #执行业务函数,并分别赋值 return jsonify({ #将处理后的数据 以JSON格式返回 "success": success, "message": message, "data": result })

【注意】:

  1. 前端请求的 URL(接口地址)必须和后端定义的接口路径一致
  2. 前端所写请求方式要与后端所写的方式保持一致。
  3. 前端请求体中JSON中的字段名要与后端代码中的对应。

五、总结

通过这个库存扣减系统的练习,我发现,命令行脚本适合帮助我们理解业务逻辑,而接口化代码则进一步接近真实项目开发。当前端通过 JS 发送 JSON 请求,后端接收参数、调用业务函数并返回 JSON 结果时,我们也就真正理解了前后端是如何联通的。

这类练习看起来简单,但非常适合打基础。所以可以自己动手改一改:增加商品、修改库存规则、加入取消订单逻辑,或者尝试把代码接入前端页面。

http://www.cnnetsun.cn/news/3162885.html

相关文章:

  • 【动态规划算法】专题五——子序列问题
  • This is Going to Sound Crazy, But What If We Used Large Language Models to Boost Automatic Databa...
  • 微信怎么给别人定时发消息?定时消息助手下载
  • Gemini 复制到 word 格式问题频繁出现?AI 导出鸭一站式修复排版错乱难题
  • LangFlow 1.x 系列【5】可视化编辑页面功能说明
  • Web安全从入门到实战:一份430页的系统学习路线与CTF渗透指南
  • 电池寿命预测精度提升40%:BatteryML开源工具深度解析
  • Windows 11 开始菜单自定义:4项注册表键值详解与隐藏推荐区域
  • Linux 安装和卸载图形化界面
  • cmake知识
  • CSUR:城市天际线道路系统的终极解决方案,告别单调道路设计
  • Codex++ v1.2.13下载和使用教程 最新更新:修复 MS Store 版 Codex 检测问题,兼容 Codex 26.611
  • AI 全栈开发实战(11):CI/CD 与自动化测试——从 pytest 到 GitHub Actions
  • Codex App 26.616 新功能教程:Record Replay 录制与回放使用指南
  • AI 全栈开发实战(15):全系列总结——从零到一做一个真正的 AI 产品
  • MS10-018漏洞深度剖析:从内存破坏原理到Metasploit实战利用
  • F3闪存检测工具:3步识别扩容盘,保护你的数据安全
  • Vue Picture Swipe:如何在5分钟内为你的Vue应用添加专业图片画廊
  • 26. 【C语言】编译前的“文本大师”:预处理器指令
  • web-第7次课后作业-2
  • C语言 操作符 (按位与) | (按位或) ^ (按位异或)
  • SDC命令详解:使用source命令读取脚本
  • topics in life
  • 如何利用downr1n实现iOS设备有线降级与越狱的完整指南
  • C语言 结构体(上)
  • 跨平台macOS组件下载神器:gibMacOS完全指南
  • 深耕 XR 安卓底软开发:Framework 定制、渲染优化与系统稳定性实战
  • TVA对具身智能领域的核心技术支撑(20)
  • 不同进程的线程切换**不一定引起进程切换**,但**必然涉及进程上下文切换(即进程切换)**——这里需要明确概念辨析
  • CCB(Change Control Board,变更控制委员会)是一个由项目干系人代表组成的正式团体