Python中堪称神仙的6个内置函数
Python 里有些内置函数,平时看着不显山不露水,真写业务、做脚本、跑数据的时候,能明显感觉代码短了一截,脑子也省了一半。
这篇不铺大词,直接挑 6 个我自己平时用得很顺手的。不是那种“知道名字但很少真用”的函数,而是你写几次就容易留下来的那种。
1)enumerate():少写下标,循环立刻顺手
很多人刚开始写循环,喜欢这样来:
names = ["alice", "bob", "tom"]
for i in range(len(names)):
print(i, names[i])
这不算错,就是有点绕。真正常写的一般会直接换成 enumerate():
names = ["alice", "bob", "tom"]
for idx, name in enumerate(names, start=1):
print(f"{idx}: {name}")
start=1 这个参数很实用,尤其是导出序号、排行榜、分页结果的时候,不用再手动 +1。
我自己在处理日志文件时也经常这么写,定位第几行异常很方便:
with open("app.log", "r", encoding="utf-8") as f:
for line_no, line in enumerate(f, start=1):
if"ERROR"in line:
print(f"第{line_no}行有异常: {line.strip()}")
这种写法比自己维护一个计数器干净很多。
2)zip():两个列表一起走,配对特别稳
有时候我们拿到两组数据,本质上就是一一对应的。比如用户名和分数:
users = ["u01", "u02", "u03"]
scores = [88, 92, 79]
for user, score in zip(users, scores):
print(user, score)
输出就是天然配好的。
我平时更常拿它做字典构造:
fields = ["id", "name", "age"]
values = [101, "东哥", 18]
row = dict(zip(fields, values))
print(row)
# {'id': 101, 'name': '东哥', 'age': 18}
接口参数组装、CSV 列头和数据拼装,这个写法都挺顺。
还有个场景也挺常见,批量比对新老数据:
old = [10, 20, 30]
new = [10, 25, 28]
for before, after in zip(old, new):
if before != after:
print(f"数据变化: {before} -> {after}")
这种代码一眼就能看懂。
3)sorted():排序不改原对象,线上代码更稳一点
排序最怕两件事:一是写得啰嗦,二是不小心把原数据改了。
sorted() 的好处就是返回新列表,不碰原数据:
orders = [
{"id": 1, "amount": 99},
{"id": 2, "amount": 15},
{"id": 3, "amount": 56},
]
result = sorted(orders, key=lambda x: x["amount"], reverse=True)
print(result)
如果你只是想拿一个排好序的结果继续处理,sorted() 比 list.sort() 更稳。
我自己比较常见的写法是按多字段排序,比如先按状态,再按创建时间:
tasks = [
{"name": "job1", "status": 2, "ts": 1701},
{"name": "job2", "status": 1, "ts": 1705},
{"name": "job3", "status": 1, "ts": 1702},
]
tasks = sorted(tasks, key=lambda x: (x["status"], x["ts"]))
这比手写一堆 if 判断省事得多。
4)any():判断“只要有一个满足”时非常省
以前经常看到这样的代码:
has_error = False
for line in lines:
if"ERROR"in line:
has_error = True
break
这个逻辑其实就是 any():
lines = ["INFO start", "WARN timeout", "ERROR db down"]
has_error = any("ERROR"in line for line in lines)
print(has_error) # True
写校验的时候很顺手。比如密码规则里,只要有一个数字:
password = "abcx9yz"
ifnot any(ch.isdigit() for ch in password):
print("密码至少要包含一个数字")
这类代码短,而且语义很直接。看一眼基本就知道在干嘛。
5)all():一组条件必须全满足,特别适合参数校验
all() 和 any() 经常一起记。
比如接口参数到了服务层,先做一层简单校验:
payload = {
"user_id": "1001",
"mobile": "13800001111",
"city": "shanghai"
}
ok = all(payload.get(k) for k in ["user_id", "mobile", "city"])
print(ok)
再比如检查一批任务是否都执行成功:
results = [True, True, True, False]
ifnot all(results):
print("有任务没跑成功")
我之前写批处理脚本时,最后就喜欢来一把这个:
files = ["a.txt", "b.txt", "c.txt"]
done = all(name.endswith(".txt") for name in files)
print(done)
这种地方不用 all() 也能写,但会多出不少样板代码。
6)map():简单转换时真挺快,尤其配合函数用
很多人对 map() 有点犹豫,主要是因为列表推导式也很好用。这个没问题,但有些场景下 map() 还是很顺。
比如把字符串数字转成整数:
raw = ["10", "20", "30", "40"]
nums = list(map(int, raw))
print(nums)
再比如批量清洗字符串:
raw_users = [" alice ", " BOB ", " Tom "]
defnormalize(name: str) -> str:
return name.strip().lower()
users = list(map(normalize, raw_users))
print(users)
如果转换动作已经是一个现成函数,map() 写出来会很自然。
当然,稍微复杂一点的逻辑,我还是更偏向列表推导式。比如要带条件过滤、字段组合,那就别硬上 map() 了,读起来反而费劲。