如何让Python的assert断言显示失败的实际值?纯Python实现
在Python中增强assert断言,显示实际值的方法
当然可以通过纯Python实现,让断言失败时自动展示预期值和实际值,不用每次手动拼接错误信息。
方法1:自定义断言函数(简单直接)
写一个封装好的断言函数,专门处理常见的检查场景(类似gtest的EXPECT_EQ),失败时自动输出预期和实际值:
def assert_eq(expected, actual, msg=None): if expected != actual: error_msg = f"Assertion failed: expected {repr(expected)}, actual {repr(actual)}" if msg: error_msg += f" ({msg})" raise AssertionError(error_msg) def assert_gt(expected, actual, msg=None): if not actual > expected: error_msg = f"Assertion failed: expected actual > {repr(expected)}, got {repr(actual)}" if msg: error_msg += f" ({msg})" raise AssertionError(error_msg)
使用示例:
my_list = [1, 2] assert_eq(3, len(my_list))
失败时输出:
AssertionError: Assertion failed: expected 3, actual 2
你可以根据需求扩展出assert_lt(小于)、assert_in(包含)等更多断言类型,覆盖不同场景。
方法2:自动解析断言表达式(更接近gtest体验)
利用inspect模块获取调用栈和断言表达式,自动解析出左右两边的实际值,写法更贴近原生assert:
import inspect def assert_check(expr): caller_frame = inspect.currentframe().f_back # 提取调用行的断言表达式字符串 line = inspect.getsource(caller_frame).strip() expr_str = line.split('assert_check(')[1].rstrip(') \n;') try: if not eval(expr, caller_frame.f_globals, caller_frame.f_locals): # 处理常见比较操作符 ops_map = { '==': ('Expected', 'Actual'), '!=': ('Unexpected', 'Actual'), '>': ('Expected greater than', 'Actual'), '<': ('Expected less than', 'Actual') } for op, (desc1, desc2) in ops_map.items(): if op in expr_str: left_part, right_part = expr_str.split(op, 1) left_val = eval(left_part.strip(), caller_frame.f_globals, caller_frame.f_locals) right_val = eval(right_part.strip(), caller_frame.f_globals, caller_frame.f_locals) raise AssertionError( f"Assertion failed: {expr_str}\n{desc1}: {repr(right_val)}\n{desc2}: {repr(left_val)}" ) # 未匹配到操作符的通用情况 raise AssertionError(f"Assertion failed: {expr_str}") except Exception as e: raise AssertionError(f"Failed to evaluate assertion: {expr_str}") from e
使用示例:
my_num = 7 assert_check(my_num < 5)
失败时输出:
AssertionError: Assertion failed: my_num < 5 Expected less than: 5 Actual: 7
这种方法的优势是不用手动拆分预期和实际值,但对复杂表达式(比如带逻辑运算符and/or的)解析可能不准确,可根据需求扩展解析逻辑。
注意事项
- 不建议修改全局
assert语句的行为(比如修改__builtins__),会影响整个代码环境,自定义函数是更安全的选择。 - 如果需要和原生assert保持一致(
-O模式下禁用),可以在自定义函数开头添加if not __debug__: return。
内容的提问来源于stack exchange,提问作者heretoinfinity
相关产品推荐
相关产品推荐

