Assert不是运行时校验工具,仅用于开发阶段调试;生产环境启用-O等优化参数后,所有assert被彻底忽略,条件表达式甚至不执行,故可能“不报错”。

Assert 不是运行时校验工具,它只在开发阶段起作用;生产环境启用优化参数(如 Python 的 -O、Java 的默认关闭、C 的 NDEBUG)后,所有 assert 都会被彻底移除或忽略。
Python 中 assert 为什么有时“不报错”
常见现象:写了 assert x > 0,但程序跑通了,没抛 AssertionError——大概率是用了 python -O script.py 启动,或者 IDE 运行配置里默认加了 -O。
- Python 的
assert是解释器级开关:-O会直接跳过所有assert字节码,连条件表达式都不执行 - 别在 assert 里放副作用逻辑,例如
assert log_call() == "ok",-O 模式下log_call()根本不会调用 - 测试中用 Pytest 时,
assert被重写为带 diff 的失败报告,但这不改变它本身仍受-O影响的事实 - 若需稳定生效的校验,改用
raise ValueError或if not condition: raise ...
Java 中 assert 默认完全不执行
写了 assert count > 0; 却毫无反应?不是 bug,是 JVM 默认禁用断言——哪怕编译进了 class 文件,运行时不加参数就等于没写。
- 必须显式启动:
java -ea MyApp(-ea= enable assertions),IDE 运行配置也要手动加 - 不要在 public 方法入口用 assert 做参数检查:生产环境关闭后,空指针/越界等错误直接暴露给调用方
- Android 平台无视
-ea,assert永远无效;某些云平台也不允许传 JVM 参数 - 失败抛的是
AssertionError(继承自Error),catch (Exception e)捕不到,日志可能静默丢失
C 语言 assert 宏的编译期开关机制
assert(expr) 看似函数,实为宏,行为由预处理器控制;发布版本常因定义 NDEBUG 导致整行消失。
- 必须包含
#include,否则编译失败 - 调试时未定义
NDEBUG:expr 被求值,为假则打印文件名/行号并调用abort() - 发布前加
#define NDEBUG再 include,assert宏展开为空,零开销 - 每个
assert只检查一个条件,避免assert(a > 0 && b 失败时无法定位具体哪个子条件错
跨语言共性:哪些地方绝对不能用 assert
所有语言中,assert 的设计目标一致:拦截开发者自己应保证成立的内部假设。一旦混淆边界,上线后必然出问题。
- 用户输入校验(如表单提交的邮箱格式)→ 必须用 if + 显式异常
- 外部资源状态(文件是否存在、网络是否可达、数据库连接成功)→ 属于运行时不确定性,assert 无意义
- 涉及 I/O、锁、内存分配等有副作用的操作 →
assert(fopen(...) != NULL)在 NDEBUG 下跳过,后续直接 crash - 需要被上层捕获并恢复的错误 →
AssertionError不该被业务逻辑处理,它意味着“代码已不可信”
最容易被忽略的一点:断言失败不是“程序出错了”,而是“程序员写错了”。它的价值不在拦住错误,而在让错误立刻暴露——所以错误信息必须包含关键变量当前值,而不是笼统说“条件不满足”。










