Python 的内置函数不需要导入即可调用,覆盖数值计算、类型转换、迭代处理和输入输出等常见任务。真正需要掌握的并不是函数名,而是它们的返回类型、边界行为,以及什么时候应该用内置函数替代手写循环。
数值与类型:结果可能和直觉不同
先看三道题,尝试在运行代码前判断输出:
print(round(2.5), round(3.5))
print(bool([]), bool([0]))
print(int("101", 2))
答案是:
2 4
False True
5
round() 在恰好位于两个整数中间时,会选择偶数方向的结果。因此 2.5 得到 2,3.5 得到 4。浮点数还存在二进制表示误差,所以涉及金额或严格小数规则时,应考虑 decimal.Decimal,不要仅依赖 round()。
bool() 判断的是对象的真值。空容器、零和 None 通常为假;非空容器为真,其中保存的元素是不是零并不影响容器本身的真值。
int() 不只用于把十进制字符串转成整数。第二个参数可以指定进制,例如 int("101", 2) 会把二进制字符串解析为十进制整数 5。
类型转换失败时通常会抛出异常。面对外部输入,可以明确处理错误:
def parse_port(raw: str) -> int:
try:
port = int(raw)
except ValueError as exc:
raise ValueError(f"端口必须是整数:{raw!r}") from exc
if not 1 <= port <= 65535:
raise ValueError("端口必须位于 1 到 65535 之间")
return port
print(parse_port("8080"))
迭代器:一行代码背后的消费行为
sum()、min()、max()、sorted()、any() 和 all() 都能处理可迭代对象,但它们并不具有相同的执行特征。
numbers = [7, 2, 9, 4]
print(sum(numbers))
print(min(numbers), max(numbers))
print(sorted(numbers))
print(numbers)
sorted() 返回新列表,不会修改原对象;列表的 .sort() 方法则会原地排序并返回 None。如果后续代码仍依赖原始顺序,sorted() 通常更稳妥。
any() 和 all() 会短路求值。any() 找到第一个真值就停止,all() 找到第一个假值就停止:
def check(value: int) -> bool:
print(f"检查 {value}")
return value > 3
print(any(check(x) for x in [1, 2, 5, 8]))
程序不会检查 8,因为处理到 5 时结果已经确定。这个特性适合存在昂贵计算的校验流程,但生成器中的副作用也可能因此只执行一部分。
另一个容易忽略的边界是空输入:
print(sum([])) # 0
print(any([])) # False
print(all([])) # True
all([]) 为 True 源于逻辑上的“空真”。如果业务规则要求“至少有一项并且全部通过”,必须额外检查集合是否非空:
checks = []
passed = bool(checks) and all(checks)
print(passed) # False
把多个序列放进同一个循环
enumerate() 和 zip() 可以消除大量手写索引,让循环直接表达意图:
names = ["Ada", "Linus", "Guido"]
scores = [95, 88, 91]
for rank, (name, score) in enumerate(zip(names, scores), start=1):
print(f"{rank}. {name}: {score}")
不过,zip() 默认会在最短序列结束时停止。长度不一致可能意味着数据错误时,可以在支持 strict 参数的 Python 版本中这样实践:
names = ["Ada", "Linus"]
scores = [95]
try:
for name, score in zip(names, scores, strict=True):
print(name, score)
except ValueError as exc:
print(f"数据长度不一致:{exc}")
map() 和 filter() 也会返回惰性迭代器。简单转换经常用列表推导式更易读;需要流式处理大量数据时,保留迭代器则可以减少中间列表占用的内存。
可复制运行的综合小测
下面的脚本只使用标准 Python,可以保存为 builtins_quiz.py 后运行。它覆盖类型转换、排序、聚合、短路判断、序列组合和安全输入处理。
from collections.abc import Callable
Question = tuple[str, Callable[[], object], object]
questions: list[Question] = [
("二进制 111 的十进制值", lambda: int("111", 2), 7),
("绝对值", lambda: abs(-12), 12),
("按长度排序", lambda: sorted(["pear", "fig", "apple"], key=len),
["fig", "pear", "apple"]),
("是否存在偶数", lambda: any(x % 2 == 0 for x in [1, 3, 6]), True),
("是否全部为正数", lambda: all(x > 0 for x in [2, 5, 9]), True),
("带起始值的求和", lambda: sum([2, 3, 4], start=10), 19),
]
score = 0
for index, (label, operation, expected) in enumerate(questions, start=1):
actual = operation()
passed = actual == expected
score += int(passed)
print(f"{index}. {label}: {actual!r} - {'通过' if passed else '失败'}")
print(f"得分:{score}/{len(questions)}")
运行命令:
python builtins_quiz.py
可以继续给 questions 增加案例,例如测试 max(..., key=...)、reversed() 或 format()。每个案例同时记录预期结果,比只阅读函数列表更容易暴露理解偏差。
I/O 与命名陷阱
input() 总是返回字符串,即使用户输入的是数字。可以这样实践一个可重复提示的整数读取函数:
def read_age() -> int:
while True:
raw = input("请输入年龄:").strip()
try:
age = int(raw)
except ValueError:
print("请输入整数。")
continue
if 0 <= age <= 150:
return age
print("年龄必须位于 0 到 150 之间。")
print(f"记录的年龄:{read_age()}")
同时要避免把变量命名为 list、str、sum、max 或 input。这些名称会遮蔽同名内置函数:
sum = 42
# sum([1, 2, 3]) # TypeError: 'int' object is not callable
如果在交互环境中不慎发生遮蔽,可以删除变量恢复名称解析:
del sum
print(sum([1, 2, 3]))
在正式代码中,直接使用 total、items、text 等更具体的变量名更清晰。
采用时检查这几件事
使用内置函数前,可以快速确认四个问题:输入是一次性迭代器还是可重复遍历的容器;函数返回新对象还是原地修改;空输入会得到什么;转换失败会抛出哪种异常。
优先选择能准确表达意图的内置函数,但不要为了压缩行数牺牲错误处理。sum(values) 通常比手写累加循环清楚,而外部输入的 int(raw) 则应配合异常处理和业务范围校验。理解这些边界后,内置函数才不只是语法捷径,而是可靠、可读的基础工具。