Python技术迷

Python 新版本的内置函数太香了!

有些 Python 代码,我一看就知道是版本没跟上。

最典型的味道就是:一边写着 while True,一边手动抓 StopIteration;调个异步迭代器,还自己包一层 try/except;数据对齐默认当它没问题,结果 zip 悄悄把尾巴截了,线上对账少几条还以为是上游丢数据。

这种坑,不是不会写,是写得太老了。

这两年 Python 自带的几个内置函数,真是越用越顺手。不是那种“语法糖看着高级”,而是你在日志处理、批量校验、异步拉数这些脏活里,能少写很多别扭代码。像 breakpoint() 在 3.7 加进来,aiter()、anext() 在 3.10 进内置函数,zip() 也多了 strict=True 这种很实用的参数。官方文档写得很清楚,这几个点都不是民间偏方,是正经支持的能力。

先说 breakpoint()。

以前我排一个清洗脚本,顺手就是:

import pdb

defnormalize_row(row):
if"amount"notin row:
        pdb.set_trace()
    row["amount"] = int(row["amount"])
return row

现在基本直接改成:

defnormalize_row(row):
if"amount"notin row:
        breakpoint()
    row["amount"] = int(row["amount"])
return row

别小看少这一行。排障时最烦的不是多打几个字,是你一边改代码一边临时插 import pdb,改完还得删。breakpoint() 从 3.7 起就是内置的,默认会走调试钩子,拿来替代 pdb.set_trace() 很顺。

再说一个很多人还没养成习惯的:zip(strict=True)。

这个我是真嫌弃以前那种“默认截短也没事”的写法。对账脚本、导出校验、字段映射,只要你心里预期两边长度必须一致,就不该默默吞掉。

user_ids = [101, 102, 103]
scores = [88, 91]

for uid, score in zip(user_ids, scores, strict=True):
    print(uid, score)

这段代码不会像老 zip() 一样只跑两轮,然后把 103 悄悄吃掉。长度不一致,直接 ValueError。这玩意是 Python 3.10 加的,官方文档甚至明确建议:如果你假设多个可迭代对象长度相等,最好开 strict=True。

线上最怕的不是报错,最怕的是不报错,还给你一个看着像对的结果。zip(strict=True) 就属于那种“早点炸比晚点查舒服太多”的东西。

再往下,是异步代码里很好用的 aiter() 和 anext()。

以前处理异步分页流,代码经常写得绕。尤其你只想“先拿一条看看”,结果还得自己维护异步迭代协议。现在内置函数直接给你补齐了。

import asyncio

classLogStream:
def__init__(self):
        self.items = iter([
            {"trace_id": "a1", "cost": 12},
            {"trace_id": "a2", "cost": 37},
        ])

def__aiter__(self):
return self

asyncdef__anext__(self):
await asyncio.sleep(0.01)
try:
return next(self.items)
except StopIteration:
raise StopAsyncIteration

asyncdefmain():
    stream = LogStream()
    it = aiter(stream)

    first = await anext(it, None)
    print("first =", first)

    second = await anext(it, None)
    print("second =", second)

    third = await anext(it, None)
    print("third =", third)

asyncio.run(main())

这里最顺手的是 await anext(it, None)。没有数据了就给默认值,不用你自己再包一层异常分支。Python 文档也写了,aiter()、anext() 是 iter()、next() 的异步对应物,都是 3.10 新增。

这种写法在拉异步接口分页、消费异步消息流、读取 websocket 推送时都挺实用。你只拿一条预读,或者做超时前的兜底判断,代码会干净很多。

我现在越来越明显的一个感觉是:Python 新版本好用,不是因为“特性更多了”,而是很多过去要自己凑的边角料,慢慢被放进内置层了。调试有 breakpoint(),异步迭代有 aiter()、anext(),并行遍历担心数据错位就上 zip(strict=True)。这些东西单看都不大,真写业务脚本的时候,一行顶三行,关键还少坑。

所以别老抱着几年前那套写法不放。很多代码不是逻辑复杂,是工具太旧,写得别扭。Python 新版本这几个内置函数,确实香,而且不是闻着香,是上线前就能少踩两个坑。