当前位置:首页>python>不再写Python for 循环

不再写Python for 循环

  • 2026-09-02 17:01:16
不再写Python for 循环

有段 Python 代码我现在看到就想改:

total = 0

for row in orders:
if row["status"] == "paid":
        total += row["amount"]

代码没错,跑起来也没毛病。

但这种 for 循环在项目里一多,代码会慢慢变成一种很熟悉的味道:建个变量,循环,判断,再修改变量。

尤其是数据清洗、日志处理、批量校验这类代码,几十行看下来,全是 for。

我现在写 Python,碰到循环一般不会马上敲 for,先看一眼:我到底是在遍历,还是只想得到一个结果?

这两个东西差别挺大。

上面那段代码,我会直接写:

paid_amount = sum(
    item["amount"]
for item in orders
if item["status"] == "paid"
)

不是为了少写几行。

而是我真正关心的是“已支付订单金额总和”,不是“怎么把 total 从 0 一点点加上去”。

这种代码后面改起来也轻松。

比如过滤掉退款订单:

paid_amount = sum(
    item["amount"]
for item in orders
if item["status"] == "paid"andnot item["refunded"]
)

逻辑基本都在一块,不需要顺着循环去找哪个变量被改了。

我平时做批量校验时更明显。

以前有人会这么写:

invalid_found = False

for record in import_rows:
ifnot record.get("mobile"):
        invalid_found = True
break

if invalid_found:
raise ValueError("导入数据存在空手机号")

这种代码我一般直接换成 any():

if any(not row.get("mobile") for row in import_rows):
raise ValueError("导入数据存在空手机号")

如果业务要求是“所有记录都必须通过校验”,那就是 all():

ready = all(
    row.get("user_id") and row.get("amount", 0) > 0
for row in import_rows
)

ifnot ready:
raise ValueError("导入数据校验失败")

any() 和 all() 有个地方挺实用:它们会短路。

any() 找到第一个 True 就停,all() 碰到第一个 False 就停。做几万条记录的前置校验时,我更愿意用这种写法,不会傻乎乎把后面的数据全部扫完。

还有一种循环,我见得更多:纯粹为了组装一个新列表。

user_ids = []

for user in users:
if user["enabled"]:
        user_ids.append(user["id"])

这种没什么好犹豫的:

user_ids = [
    user["id"]
for user in users
if user["enabled"]
]

字典也是一样。

比如接口返回了一批商品,需要按 SKU 建索引,后面查价格:

price_by_sku = {
    item["sku"]: item["sale_price"]
for item in products
if item["sale_price"] isnotNone
}

后面直接:

price = price_by_sku.get(target_sku)

不用再为了查一个 SKU 重复扫描整个列表。

这里我比较嫌弃的一种代码,是循环里面不断查列表:

for sku in request_skus:
for item in products:
if item["sku"] == sku:
# ...
break

数据量小时看不出来,数据一上来就开始难受。

我一般先把数据做成索引,再处理:

product_map = {
    item["sku"]: item
for item in products
}

matched = [
    product_map[sku]
for sku in request_skus
if sku in product_map
]

代码只是少了一层循环,执行方式已经不是一回事了。

再碰到日志处理,我也很少手写循环计数。

比如从一批日志里统计 ERROR:

error_count = sum(
1
for line in log_lines
if" ERROR "in line
)

想拿第一条超时日志:

timeout_line = next(
    (line for line in log_lines if"timeout"in line.lower()),
None
)

以前这种需求特别容易写成:

timeout_line = None

for line in log_lines:
if"timeout"in line.lower():
        timeout_line = line
break

能跑,但读代码的人得自己脑补一句:“哦,他其实只是想找第一条。”

next() 已经把这个意图写出来了。

不过我不会为了“不写 for”硬上 map()、filter()。

这种:

names = list(map(lambda x: x["name"], users))

我反而觉得不如:

names = [user["name"] for user in users]

Python 代码不是越函数式越高级。lambda 套多了之后,调试的时候一样难受。

还有一种情况更不能硬改:循环里面有明显副作用。

for task in pending_tasks:
try:
        push_task(task)
        mark_success(task["id"])
except Exception:
        logger.exception("push failed, task_id=%s", task["id"])

这里有接口调用、有状态修改、有异常处理。

这种 for 我留着。

你真把它塞进 map(),代码不会更 Python,只会更别扭。

所以我现在所谓的“不再写 Python for 循环”,并不是项目里彻底看不到 for。

而是少写这种东西:

初始化变量 → 循环 → 判断 → append / 累加 / 改状态。

看到这套结构,我通常先试一下 sum()、any()、all()、next()、推导式或者生成器。

能直接描述结果,就别把执行步骤一行一行摊开。

for 当然没问题。

问题是有些代码明明只想问一句“有没有”“一共有多少”“找第一个”“转换成什么”,最后却写成十几行循环。

这种 for,我现在基本不留。

最新文章

随机文章