Python技术迷

Python中堪称神仙的6个内置函数

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() 了,读起来反而费劲。