很多 Python 开发者习惯遇到问题先翻第三方库,却忽略了标准解释器里那几十个随时可用、无需 import 的内置函数。它们覆盖数学运算、类型转换、迭代处理和 I/O,熟练掌握后,一段十行的手写循环往往能压缩到一行——而且更易读。
数学运算:一行代码替代手写循环
sum()、max()、min()、abs()、round() 是最常用的数学类内置函数。新手容易写出这样的累加:
total = 0
for price in prices:
total += price
直接用 sum(prices) 即可。max 和 min 同理——它们还支持 key 参数,按自定义规则取极值:
# 按销量找最畅销商品
best = max(products, key=lambda p: p["sales"])
round() 的第二个参数控制小数位数,round(3.1415, 2) 得 3.14。注意银行家舍入规则:round(2.5) 返回 2 而非 3,需要四舍五入时用 decimal.Decimal.quantize。
divmod(a, b) 同时返回商和余数,在分页、时间换算场景很实用:
minutes, seconds = divmod(3723, 60) # 62 分 3 秒
数据类型转换与检查:别再 isinstance 一把梭
int()、float()、str()、bool() 做显式转换人人都会,但几个容易忽略的细节值得记住:
bool(0)、bool("")、bool([])、bool(None)都是False,其余为True——写条件判断时直接if items:比if len(items) > 0:更 Pythonic。int("0xff", 16)支持指定进制,解析配置里的十六进制字符串不用正则。
类型检查方面,type() 返回对象类型,isinstance() 判断是否属于某类型或其子类。日常用 isinstance 就够了,type 只在需要精确匹配(不含子类)时才用。
issubclass() 判断类间继承关系,写插件注册机制时比手动查 __bases__ 清晰得多。
迭代处理:map / filter / zip 的实战场景
处理可迭代对象是内置函数最密集的区域。len()、sorted()、reversed()、enumerate()、zip()、map()、filter()、any()、all() 各有适用场景。
enumerate——遍历同时拿索引,告别 range(len(...)):
for idx, name in enumerate(students, start=1):
print(f"{idx}. {name}")
zip——并行迭代多个序列,比手动索引对齐安全得多:
ids = [101, 102, 103]
names = ["Alice", "Bob", "Carol"]
roster = dict(zip(ids, names)) # {101: 'Alice', 102: 'Bob', 103: 'Carol'}
map / filter——函数式风格处理序列。列表推导式往往更直观,但在需要复用已有函数时 map 更简洁:
# 对一批字符串统一去空格、转小写
cleaned = list(map(str.lower, map(str.strip, raw_texts)))
any / all——短路判断,避免逐个循环:
if any(log.level == "ERROR" for log in logs):
alert_ops_team()
sorted() 的 key 和 reverse 参数几乎能满足所有排序需求,不必自己实现比较函数:
# 多字段排序:先按优先级降序,再按创建时间升序
tasks_sorted = sorted(tasks, key=lambda t: (-t["priority"], t["created_at"]))
I/O 与调试:print 之外的实用工具
print() 的 sep 和 end 参数能省掉字符串拼接:
print(*columns, sep="|", end="\n") # 表格风格输出
input() 读取用户输入,open() 配合上下文管理器读写文件——这是基础,但 repr() 常被忽略。调试时 repr(obj) 给出带类型的明确表示,str(obj) 倾向可读表示。日志里用 repr 能避免 "None" 和 None 混淆。
format() 和 f-string 共享同一套格式规范:
format(0.85, ".2%") # '85.00%'
f"{0.85:.2%}" # 同样结果,更直观
实战:用内置函数重构一段真实代码
下面是一段模拟的业务代码——从日志列表中筛选错误、汇总统计、格式化输出。先用"手写一切"的风格,再用内置函数重构。
重构前:
logs = [
{"level": "INFO", "msg": "start", "ts": 1},
{"level": "ERROR", "msg": "disk full", "ts": 5},
{"level": "ERROR", "msg": "timeout", "ts": 8},
{"level": "INFO", "msg": "end", "ts": 12},
]
errors = []
for log in logs:
if log["level"] == "ERROR":
errors.append(log)
count = 0
for e in errors:
count += 1
first_ts = None
for e in errors:
if first_ts is None or e["ts"] < first_ts:
first_ts = e["ts"]
last_ts = None
for e in errors:
if last_ts is None or e["ts"] > last_ts:
last_ts = e["ts"]
msgs = []
for e in errors:
msgs.append(e["msg"])
report = "Errors: " + str(count) + ", from " + str(first_ts) + " to " + str(last_ts) + " — " + " | ".join(msgs)
print(report)
重构后:
logs = [
{"level": "INFO", "msg": "start", "ts": 1},
{"level": "ERROR", "msg": "disk full", "ts": 5},
{"level": "ERROR", "msg": "timeout", "ts": 8},
{"level": "INFO", "msg": "end", "ts": 12},
]
errors = [log for log in logs if log["level"] == "ERROR"]
count = len(errors)
first_ts = min(e["ts"] for e in errors)
last_ts = max(e["ts"] for e in errors)
msgs = [e["msg"] for e in errors]
print(f"Errors: {count}, from {first_ts} to {last_ts} — {' | '.join(msgs)}")
输出均为:
Errors: 2, from 5 to 8 — disk full | timeout
行数从 22 行降到 9 行,逻辑更清晰:筛选用推导式,计数用 len,极值用 min/max,拼接用 f-string 和 join。每个操作对应一个内置函数,阅读时不需要追踪循环状态变量。
选用建议与避坑清单
- 优先用内置函数,再考虑列表推导式,最后才写显式循环——这三层优先级能让代码越来越 Pythonic。
map/filtervs 推导式:简单变换用推导式更易读;需要复用已有命名函数时map更简洁。别在同一项目里混用两种风格。sorted返回新列表,reversed返回迭代器——对大序列用reversed可以省内存,但只能遍历一次。zip在不等长序列上会截断。需要完整配对时用itertools.zip_longest。round的银行家舍入在财务场景会出意外,换Decimal.quantize。any/all是短路的——找到第一个 True/False 就停,别在生成器里放有副作用的操作。
内置函数不需要安装、不需要导入、不需要版本兼容顾虑。花一小时把 dir(__builtins__) 里的名字过一遍,比学一个新框架的回报更直接。