Python 语法练习不能只停留在基础语法:从库存扣减业务理解代码逻辑 很多人在学习 Python 时包括我自己最开始也是一直停留在变量、判断、循环、字典、函数这些基础语法的练习上。语法本身并不难真正难的是如何把一个真实业务场景拆解成程序可以执行的代码逻辑。所以这类练习不能只是写几个if、for、while而应该从业务流程出发先理解业务规则再把规则转换成代码判断、数据结构和执行流程。整体训练路径如下业务规则理解 ↓ 命令行脚本实现 ↓ 函数封装 ↓ 接口化改造 ↓ 前端页面调用接口 ↓ 接口文档整理本文先完成前两个阶段业务规则拆解 命令行脚本实现。以下是 我让GPT帮我生成的Python 基础语法训练的练习题不仅可以练习python的语法还能够加深自己对于业务场景的理解还能够深入的了解到前后端是如何进行联通的。一、业务需求原题库存扣减系统业务背景假设某系统中有商品库存products { P001: {name: 鼠标, stock: 10, price: 50}, P002: {name: 键盘, stock: 5, price: 120}, P003: {name: 显示器, stock: 3, price: 899} }用户下单规则商品编号必须存在购买数量必须大于 0购买数量不能超过库存下单成功后扣减库存下单失败不能扣减库存题目 1单商品下单用户输入商品编号 购买数量程序判断是否可以下单。下单成功输出下单成功 商品名称 购买数量 订单金额 剩余库存下单失败输出具体原因。题目 2多商品购物车下单用户可以连续输入多个商品和数量。要求输入q结束添加商品商品不存在时提示错误库存不足时提示错误成功添加到购物车后先不扣库存用户确认下单后再统一扣减库存输出订单总金额题目 3库存预占逻辑在多商品购物车基础上增加“库存预占”。规则添加商品到购物车成功后库存进入预占状态预占库存不允许被其他订单使用用户取消订单时释放预占库存用户确认订单时预占库存正式扣减你需要设计两个字段stock locked_stock要求实现查询可售库存添加购物车时增加 locked_stock取消订单时减少 locked_stock确认订单时减少 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 题目二 多商品购物车下单题目二在题目一的基础上增加了购物车逻辑。用户可以连续输入多个商品和数量规则如下输入q结束添加商品商品不存在时提示错误库存不足时提示错误成功添加到购物车后先不扣库存用户确认下单后再统一扣减库存输出订单总金额对于这一题来说我们可以把这个业务想象成去超市推着购物车购物加车阶段你在货架前挑选商品往购物车里放。此时你只是把东西放进车里超市货架上的商品并没有真正变少但你需要边拿边看货架上还有没有所以会考虑库存的问题。结算阶段你推着购物车去收银台。收银员帮你计算总价。扣减阶段你付了钱也就是确认下单超市后台库存系统才真正把这些商品数量减掉。要实现这个复杂的流程我们需要解决两个核心问题怎么代表“购物车”—— 用一个新字典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 })【注意】前端请求的 URL接口地址必须和后端定义的接口路径一致前端所写请求方式要与后端所写的方式保持一致。前端请求体中JSON中的字段名要与后端代码中的对应。五、总结通过这个库存扣减系统的练习我发现命令行脚本适合帮助我们理解业务逻辑而接口化代码则进一步接近真实项目开发。当前端通过 JS 发送 JSON 请求后端接收参数、调用业务函数并返回 JSON 结果时我们也就真正理解了前后端是如何联通的。这类练习看起来简单但非常适合打基础。所以可以自己动手改一改增加商品、修改库存规则、加入取消订单逻辑或者尝试把代码接入前端页面。