在 Python 中,assert
是一个内建语句,其语义是:
“我断言某个条件必须为真,否则程序应立即中止执行。”
assert condition, message
它的核心作用是:
来看一个简单语句:
assert x > 0, "x must be positive"
Python 实际会将其转译为:
if __debug__:
if not (x > 0):
raise AssertionError("x must be positive")
__debug__
是什么?python -O
(optimize 模式)运行时,__debug__
被置为 False
这说明:assert 是非生产级防御机制。
def move(x, y):
assert isinstance(x, int) and isinstance(y, int), "x, y must be integers"
def square(x):
result = x * x
assert result >= 0
return result
def pop(stack):
assert len(stack) > 0, "Stack underflow"
return stack.pop()
这些用法源自**设计契约(Design by Contract)**编程理念。
特征 | assert |
if + raise |
---|---|---|
是否为语句 | ✅ 是 | ✅ 是 |
是否面向用户输入 | ❌ 否 | ✅ 是 |
是否保留在发布代码中 | ❌ 否(会被优化掉) | ✅ 是 |
抛出异常类型 | AssertionError(不可自定义) | 任意异常 |
是否适合做业务逻辑分支 | ❌ 否 | ✅ 是 |
是否适合做内部断言/调试断点 | ✅ 是 | ❌ 否 |
# 错误示范
assert user_input > 0, "Age must be positive" # ❌ 不稳定、提示不友好
# 正确做法
if user_input <= 0:
raise ValueError("Age must be positive") # ✅ 清晰、不会被优化移除
场景 | 是否使用 assert | 替代方案 |
---|---|---|
单元测试中验证输出 | ✅ 推荐 | unittest.assertEqual 也可 |
模块之间接口契约 | ✅ 推荐(调试阶段) | 上线后建议换为 raise |
外部 API 请求参数校验 | ❌ 禁用 | 用 pydantic , raise |
️ 用户输入处理 | ❌ 禁用 | 用 raise 抛异常 |
类内部不变量 | ✅ 推荐 | 保证对象状态合法性 |
def test_normalize():
vec = [3, 4]
result = normalize(vec)
assert math.isclose(result[0], 0.6)
assert math.isclose(result[1], 0.8)
或者用 pytest
+ assert
,测试代码简洁高效。
✅ 使用 assert 来暴露 bug,不是来处理异常
✅ 它是开发者的“自信声明”:我有理由相信这条件永远成立
❌ 不要相信用户总是行为良好,assert 无法保护你