Python assert不触发的首要原因是运行时加了-O参数,此时assert被完全移除而非失效;应检查优化级别、避免在业务逻辑中依赖assert,改用显式异常或自定义require函数。

Python assert 不触发?检查是否加了 -O 或 -OO
Python 的 assert 语句在解释器启用优化模式时会被完全移除,不是“失效”,而是压根不执行。最常见原因就是运行时加了 -O(大写字母 O)参数:python -O script.py。此时所有 assert 都被跳过,连条件表达式都不求值。
实操建议:
- 用
python -c "import sys; print(sys.flags.optimize)"查看当前优化级别:0表示正常,1表示-O,2表示-OO - CI/CD 脚本、Dockerfile 或启动脚本里容易误加
-O(比如为了“提速”或“减小体积”),务必 grep 检查 -
-OO还会丢弃文档字符串,可能影响依赖__doc__的工具(如某些测试发现逻辑),比-O更激进
别把 assert 当业务校验:它不是 if raise
assert 是开发期调试辅助,设计上就允许被禁用;而业务逻辑中的参数检查、状态校验、权限验证等,必须在任何运行环境下都生效。
常见错误现象:
立即学习“Python免费学习笔记(深入)”;
- 本地测试时
assert x > 0拦住了非法输入,上线后因-O参数直接跳过,导致后续计算出错或崩溃 - 用
assert isinstance(obj, MyType)做类型守门,结果生产环境绕过,传入错误类型引发隐晦异常
正确做法是显式抛出异常:
if not (x > 0):
raise ValueError("x must be positive")
这样既清晰表达了契约,又不受优化标志影响。
想保留断言行为?用自定义函数替代裸 assert
如果团队习惯用 assert 写轻量校验,又希望它在生产环境也起作用,可以封装一个“永远开启”的校验函数,避免误用原生 assert。
实操建议:
- 定义一个
require函数(名字比assert更明确其业务含义):
def require(condition, message="Assertion failed"):
if not condition:
raise AssertionError(message)
- 调用时写
require(x > 0, "x must be positive"),它不受-O影响,且堆栈更易读 - 注意不要给这个函数加装饰器或动态 patch,否则可能引入隐蔽的性能开销或兼容性问题
测试中依赖 assert?确保 pytest / unittest 未启用 -O
pytest 默认不加 -O,但如果你在 pyproject.toml 或 setup.cfg 中配置了 addopts = -O,或者用 python -m pytest -O 手动传参,那么测试里的 assert 也会消失——表现为测试“意外通过”,掩盖真实 bug。
排查要点:
- 运行
pytest --help | grep addopts看是否有隐式-O - 检查
pytest.ini、pyproject.toml [tool.pytest.ini_options]是否含addopts字段 - CI 中使用
python -m pytest时,确认没被 shell 别名或 wrapper 脚本悄悄加上-O
真正难察觉的点是:断言消失不会报错,只会让测试“看起来绿了”。一旦漏掉这层检查,bug 就会一路跑到线上。










