Python中能否向函数传递表达式并捕获其文本?自定义测试工具开发需求问询
在Python中捕获函数参数的表达式文本
这绝对是可行的!Python的inspect模块配合AST(抽象语法树)工具,就能完美实现你想要的功能——捕获传递给check函数的表达式文本,不用手动重复写字符串。
核心思路
当调用check()时,我们可以:
- 获取调用者的栈帧,定位到调用
check的源代码行; - 解析该行的AST,提取出第三个参数对应的表达式文本;
- 结合计算出的实际值、预期值,生成你需要的输出格式。
完整实现代码
import inspect import ast def check(description, expected, actual_expr): # 先计算表达式的实际值 actual = actual_expr # 获取调用者的栈帧(必须记得最后删除引用,避免内存泄漏) caller_frame = inspect.currentframe().f_back try: # 获取调用者的源代码行 source_lines, starting_line = inspect.getsourcelines(caller_frame) # 找到调用check的那一行(处理行号偏移) call_line_idx = caller_frame.f_lineno - starting_line call_line = source_lines[call_line_idx].strip() # 解析该行的AST,定位到check函数的调用 tree = ast.parse(call_line) expr_str = "<无法解析表达式>" for node in ast.walk(tree): if (isinstance(node, ast.Call) and hasattr(node.func, 'id') and node.func.id == 'check'): # 提取第三个参数的表达式文本 expr_str = ast.get_source_segment(call_line, node.args[2]) break finally: # 强制删除帧引用,防止内存泄漏 del caller_frame # 生成结果输出 if actual == expected: status = "passed" else: status = "failed" print(f"{description} {status}... expected: {expected} evaluated: {expr_str} got: {actual}") # 测试用例 def call_something(): return 10 def call_something_else(): return 12 a = 0 check("check the total matches", 123, a + call_something() * call_something_else())
代码说明
- 栈帧获取:
inspect.currentframe().f_back拿到调用check的上下文帧,通过这个帧我们能获取到调用位置的源代码。 - AST解析:用
ast.parse把调用行的代码转为抽象语法树,然后遍历找到check的调用节点,再用ast.get_source_segment提取第三个参数的原始表达式文本——这比字符串切割更可靠,能正确处理复杂的表达式(比如带括号、嵌套函数调用的情况)。 - 内存泄漏预防:必须手动删除栈帧引用,因为Python的垃圾回收不会自动回收栈帧对象,不删除会导致内存泄漏。
注意事项
- 源代码可访问性:这个方法需要能访问到调用代码的源代码文件,如果代码是从字符串动态执行的、或者是编译后的
.pyc文件,可能无法获取到源代码。 - 多行调用处理:如果
check的调用被拆分成多行(比如参数换行),需要修改代码把多行拼接成完整的调用语句后再解析。 - Python版本兼容:
ast.get_source_segment是Python 3.8及以上版本才有的API,如果是旧版本,可以用节点的lineno和col_offset属性手动从源代码中截取表达式。
内容的提问来源于stack exchange,提问作者Darren Oakey
相关产品推荐
相关产品推荐

