如何获取Lambda函数源码而不包含外层调用(非正则方式)
问题:提取传入Lambda函数的纯净源码
现有如下Python函数foo,通过inspect.getsource获取传入函数的源码:
def foo(function): import inspect return inspect.getsource(function)
调用foo(lambda x: x[0] + x[1]*2)时,返回结果为'foo(lambda x: x[0] + x[1]*2)\n'——包含了外层foo调用的整行代码,而非仅Lambda函数本身。期望输出仅为lambda x: x[0] + x[1]*2。
补充说明:直接使用ast.parse(inspect.getsource(function))在多行调用场景下可能失败,例如:
ast.parse(foo( lambda x: x+1))
请问是否存在无需正则表达式的实现方式?
解决方案
可以通过AST抽象语法树结合源码位置信息实现精准提取,无需正则表达式,能兼容单行、多行调用及多行Lambda的场景,实现代码如下:
import inspect import ast def foo(function): # 获取包含外层调用的源码文本 source = inspect.getsource(function) # 解析为AST语法树 tree = ast.parse(source) # 遍历AST,定位传入的Lambda节点 target_lambda = None for node in ast.walk(tree): if isinstance(node, ast.Call) and isinstance(node.func, ast.Name) and node.func.id == 'foo': # 取foo调用的第一个参数(即目标Lambda) arg = node.args[0] if isinstance(arg, ast.Lambda): target_lambda = arg break if not target_lambda: return inspect.getsource(function) # 按行拆分源码文本 lines = source.splitlines(keepends=True) start_line = target_lambda.lineno - 1 end_line = target_lambda.end_lineno - 1 # 处理单行Lambda的情况 if start_line == end_line: line_content = lines[start_line] return line_content[target_lambda.col_offset:target_lambda.end_col_offset].strip() # 处理多行Lambda的情况 else: lambda_source = [] # 截取第一行的后半部分 lambda_source.append(lines[start_line][target_lambda.col_offset:]) # 添加中间完整行 lambda_source.extend(lines[start_line+1:end_line]) # 截取最后一行的前半部分 lambda_source.append(lines[end_line][:target_lambda.end_col_offset]) return ''.join(lambda_source).strip()
测试验证
- 单行调用场景:
调用foo(lambda x: x[0] + x[1]*2),返回结果为:lambda x: x[0] + x[1]*2 - 多行调用场景:
返回结果为:foo( lambda x: x+1)lambda x: x+1 - 多行Lambda场景:
返回结果为:foo(lambda x: x[0] + x[1]*2)lambda x: \n x[0] + x[1]*2(可根据需求调整strip()或保留格式)
该方案的核心逻辑是利用AST节点自带的位置属性(行号、列偏移),精准定位Lambda函数在源码文本中的范围,从而截取到纯净的Lambda源码,完全规避了正则表达式的匹配误差问题。
内容的提问来源于stack exchange,提问作者ignoring_gravity
相关产品推荐
相关产品推荐

