Python技术迷

还在用if-else堆代码?这10个Python技巧让你的代码优雅10倍

代码里连续 7 个 if-elif,第一眼我就不太想往下看。

不是因为它一定慢。慢不慢另说,主要是这种代码最容易在第 8 个分支来的时候,把人带沟里。

尤其是面试题里问“怎么优化 if-else”,千万别上来就背设计模式。Python 里有些写法,平时处理日志、清洗字段、接口兜底、批量任务,真能少写一半废代码。

先看这个最常见的。

if status == "paid":
    action = "ship"
elif status == "refund":
    action = "stop"
elif status == "closed":
    action = "archive"
else:
    action = "wait"

这种我一般直接换成字典映射:

status_action = {
"paid": "ship",
"refund": "stop",
"closed": "archive",
}

action = status_action.get(status, "wait")

别小看这一点。分支一多,字典比 if-else 清楚太多。后面产品再加状态,你只改一行,不用在一堆判断里找位置。

第二个,函数也可以放进字典。

有些人写接口回调喜欢这么干:

if event == "user_created":
    create_user(payload)
elif event == "user_deleted":
    delete_user(payload)
elif event == "order_paid":
    mark_order(payload)

我更愿意这么写:

defignore_event(data):
    print("skip event:", data.get("event_id"))

handlers = {
"user_created": create_user,
"user_deleted": delete_user,
"order_paid": mark_order,
}

handler = handlers.get(event, ignore_event)
handler(payload)

这东西在消息消费里很好用。消费者入口别堆太多业务判断,入口只负责分发,真正的处理逻辑放到函数里。出了问题,看日志也好追。

第三个,能用提前返回,就别嵌套三层。

我见过这种代码:

defimport_row(row):
if row:
if row.get("mobile"):
if row.get("amount"):
                save_bill(row)

看着不长,但味道已经不对了。后面再加一个身份证校验、一个黑名单校验,马上变成楼梯。

我会改成这样:

defimport_row(row):
ifnot row:
return

ifnot row.get("mobile"):
return

ifnot row.get("amount"):
return

    save_bill(row)

面试的时候说这个,别只说“减少嵌套”。你要说:异常路径提前挡掉,主流程留在最下面,人看代码时不用在脑子里维护一堆缩进状态。

第四个,字段清洗别到处写 if value is None。

批量导入 Excel 时经常见这种:

if name isNone:
    name = ""
else:
    name = name.strip()

我一般写一个小函数,别让脏数据处理散得到处都是。

defclean_text(value):
if value isNone:
return""
return str(value).strip()

name = clean_text(row.get("customer_name"))
city = clean_text(row.get("city"))
remark = clean_text(row.get("remark"))

这种代码不炫,但省命。后面你发现要统一去掉全角空格,只改一个地方。

第五个,用 or 做简单兜底,但别乱用。

timeout = config.get("timeout") or3

这行没问题,配置没有就默认 3 秒。

但如果 0 是合法值,这么写就坑了。比如限流阈值允许配置 0,表示关闭:

limit = config.get("limit") or100

这就把 0 改成 100 了。这个地方我一般老老实实写:

limit = config.get("limit")
if limit isNone:
    limit = 100

优雅不是少写两行,是别把线上配置吃掉。

第六个,列表推导式适合清爽,不适合炫技。

清理一批手机号:

mobiles = []
for item in rows:
    mobile = clean_text(item.get("mobile"))
if mobile:
        mobiles.append(mobile)

可以写成:

mobiles = [
    clean_text(item.get("mobile"))
for item in rows
if clean_text(item.get("mobile"))
]

但这里我其实不太喜欢,因为 clean_text 调了两次。更稳一点:

mobiles = []

for item in rows:
    mobile = clean_text(item.get("mobile"))
if mobile:
        mobiles.append(mobile)

不是所有短代码都更好。面试里你可以讲这个判断:列表推导式适合简单转换,一旦有重复计算、有日志、有异常处理,就退回普通循环。

第七个,enumerate 别忘了用。

导入数据报错时,最怕日志只打印“手机号为空”,不告诉你第几行。

for index, row in enumerate(rows, start=2):
    mobile = clean_text(row.get("mobile"))

ifnot mobile:
        print(f"第 {index} 行手机号为空")
continue

    save_customer(row)

start=2 是因为 Excel 第一行通常是表头。这个细节挺实用,面试官一般也听得出来你不是在背语法。

第八个,zip 处理字段映射很顺手。

有时候拿到一行 CSV,是列表:

values = ["1001", "Tom", "paid"]

别手动一个个取:

order_id = values[0]
name = values[1]
status = values[2]

可以这样:

fields = ["order_id", "customer_name", "status"]
record = dict(zip(fields, values))

不过这里也要补一句:如果字段数量可能不一致,我会先校验。

if len(values) != len(fields):
raise ValueError(f"字段数量不对: {values}")

record = dict(zip(fields, values))

zip 默认会截断,多出来的数据直接没了。这个坑不提醒,导入脚本迟早背锅。

第九个,collections.defaultdict 很适合分组。

统计每个用户的订单号:

from collections import defaultdict

user_orders = defaultdict(list)

for order in orders:
    user_orders[order["user_id"]].append(order["order_id"])

不用先判断 key 在不在。

if user_id notin user_orders:
    user_orders[user_id] = []

这种判断写多了很烦,而且容易把主逻辑淹没。分组、计数、归类,defaultdict 基本够用。

第十个,异常别一把梭哈 except Exception。

有些脚本这么写:

try:
    sync_order(order)
except Exception:
pass

这代码我看到会有点火。它不是优雅,是把事故藏起来。

至少要把关键字段打出来:

try:
    sync_order(order)
except TimeoutError as e:
    print("订单同步超时:", order.get("order_id"), e)
except ValueError as e:
    print("订单数据异常:", order.get("order_id"), e)

如果确实要兜底,也别静默:

except Exception as e:
    print("未知异常:", order.get("order_id"), type(e).__name__, e)

线上最怕的不是报错,是错了你还不知道。

这些技巧单独看都不大,甚至有点碎。但代码质量很多时候就是这些碎地方堆出来的。

if-else 不是不能用,该用就用。两个分支写得清清楚楚,没必要硬改成花活。真正该动的是那种状态越来越多、校验越来越深、异常越来越糊的代码。

面试时也别只回答“用字典替代 if-else”。往下多说一句:状态分发用字典,异常路径提前返回,字段清洗集中处理,循环里保留日志和行号。

这比背十个语法糖管用。