
一批订单文件导进系统,跑到第 387 行突然停了。
日志里没什么高深异常,就一句:
ValueError: could not convert string to float: ''
金额字段是空字符串,float() 直接炸掉。更麻烦的是,脚本一停,前面处理了多少、后面还剩多少,全得重新查。
这种代码我一般不急着加 try...except。先看判断写在哪,循环有没有退出策略,函数是不是把脏数据带到了最深处。
原来的处理逻辑大概长这样:
for row in rows:
amount = float(row["amount"])
if row["status"] == "paid":
save_order(row["order_no"], amount)
代码不长,问题倒不少。
金额为空会中断;订单号缺失照样往下走;状态不是 paid 的记录虽然不会保存,但前面的转换已经执行了。判断顺序明显不对。
我会先把不能处理的数据挡在循环外层:
for row_no, row in enumerate(rows, start=2):
order_no = row.get("order_no", "").strip()
amount_text = row.get("amount", "").strip()
status = row.get("status", "").strip().lower()
if not order_no:
print(f"第 {row_no} 行跳过:订单号为空")
continue
if status != "paid":
continue
if not amount_text:
print(f"第 {row_no} 行跳过:金额为空,订单={order_no}")
continue
amount = float(amount_text)
save_order(order_no, amount)
这里的 continue 很实用。
碰到不符合条件的数据,直接结束本轮循环,不要把后续逻辑再套进三四层 if。代码一旦写成这样,基本就开始难看了:
if order_no:
if status == "paid":
if amount_text:
...
业务条件再多两个,右边能一路缩进到屏幕外面。Python 的缩进本来是帮你看结构的,不是拿来堆楼层的。
不过上面的代码还有个坑:金额只要出现 "12元"、"--" 这种内容,循环还是会中断。
这时候才该把转换单独收进函数。
def parse_amount(raw_value):
text = str(raw_value or "").strip()
if not text:
return None
try:
amount = float(text)
except ValueError:
return None
if amount <= 0:
return None
return round(amount, 2)
函数在这里不是为了展示“代码复用”,而是隔离不稳定输入。
调用方不需要知道金额怎么清洗,只需要判断结果能不能用:
failed_rows = []
saved_count = 0
for row_no, row in enumerate(rows, start=2):
order_no = str(row.get("order_no") or "").strip()
status = str(row.get("status") or "").strip().lower()
if not order_no or status != "paid":
continue
amount = parse_amount(row.get("amount"))
if amount is None:
failed_rows.append({
"row_no": row_no,
"order_no": order_no,
"reason": "金额格式错误",
})
continue
save_order(order_no, amount)
saved_count += 1
print(f"导入完成:成功 {saved_count} 条,失败 {len(failed_rows)} 条")
条件判断负责决定“这条数据该不该继续”,循环负责控制“下一条什么时候开始”,函数负责把某一段容易出错的逻辑关起来。
这三个东西放到真实代码里,本来就是一起工作的。拆开背语法,写出来很容易变成一坨判断。
for 适合明确的数据集合,while 则更适合次数不固定的过程,比如接口重试。
def push_order(order, sender, max_attempts=3):
attempt = 1
while attempt <= max_attempts:
result = sender(order)
if result.ok:
return True
print(
f"订单推送失败:order={order['order_no']} "
f"attempt={attempt} error={result.message}"
)
attempt += 1
return False
这段代码里,while 不是用来从 1 数到 3,而是表达“只要还没超过重试次数,就继续尝试”。
成功后直接 return,不用再加一个变量记录状态,也不用等循环慢慢走完。超过次数仍然失败,函数自然返回 False。
还有个细节我一直不太喜欢:函数里同时做校验、保存数据库、发送通知、打印统计。看着像一个入口解决全部问题,真出错时根本不知道该从哪一段查。
更稳一点的写法,是让每个函数只承担一个清楚的判断:
def should_import(row):
return (
bool(str(row.get("order_no") or "").strip())
and str(row.get("status") or "").lower() == "paid"
)
主流程留下真正的处理顺序:
for row in rows:
if not should_import(row):
continue
amount = parse_amount(row.get("amount"))
if amount is None:
continue
save_order(row["order_no"], amount)
代码不花哨,但出了问题很好查。
看到数据没保存,先查 should_import();进入了保存流程却报金额错误,就查 parse_amount();循环提前结束,再找有没有误用 break 或未处理异常。
条件、循环和函数真正有用的地方,不是能写出多少种语法,而是让程序在遇到脏数据、异常状态和重复任务时,仍然知道下一步该往哪走。
以上就是“Python 的条件、循环和函数,别再拆开学了!”的详细内容,想要了解更多Python教程欢迎持续关注编程学习网。
扫码二维码 获取免费视频学习资料

- 本文固定链接: http://www.phpxs.com/post/14372/
- 转载请注明:转载必须在正文中标注并保留原文链接
- 扫码: 扫上方二维码获取免费视频资料