如何从Python代码字符串中提取已定义/更新变量的标识与对应值?
解决方案:用AST逐行解析Python代码中的赋值操作
要实现逐行解析Python代码字符串、提取标识符及其赋值的需求,你可以基于ast模块构建针对性的节点访问器,同时维护一个环境字典来跟踪变量的当前值。以下是具体实现步骤和代码:
核心思路
- 逐行解析:将代码按行分割,每行单独解析为AST。
- 节点求值:编写函数将AST节点转换为实际Python值,利用环境字典解析变量引用。
- 赋值处理:通过
ast.NodeVisitor子类,针对性处理不同类型的赋值节点(普通变量、解包赋值、下标赋值),记录赋值关系并更新环境。 - 循环支持:扩展访问器处理循环节点,遍历迭代元素并处理循环体中的赋值。
完整代码实现
import ast def evaluate_node(node, env): """将AST节点转换为实际值,依赖环境字典解析变量""" if isinstance(node, ast.Constant): return node.value elif isinstance(node, ast.Name): return env.get(node.id, None) elif isinstance(node, ast.List): return [evaluate_node(elem, env) for elem in node.elements] elif isinstance(node, ast.Tuple): return tuple(evaluate_node(elem, env) for elem in node.elements) elif isinstance(node, ast.BinOp): # 扩展处理二元运算,比如 x = y + z left_val = evaluate_node(node.left, env) right_val = evaluate_node(node.right, env) if isinstance(node.op, ast.Add): return left_val + right_val elif isinstance(node.op, ast.Mult): return left_val * right_val # 可继续扩展其他运算符 return None class AssignmentVisitor(ast.NodeVisitor): def __init__(self, env): self.env = env self.assignments = {} # 存储当前语句的赋值结果 def visit_Assign(self, node): right_val = evaluate_node(node.value, self.env) for target in node.targets: self._process_target(target, right_val) self.generic_visit(node) def _process_target(self, target, value): """处理单个赋值目标节点""" if isinstance(target, ast.Name): var_id = target.id self.assignments[var_id] = value self.env[var_id] = value elif isinstance(target, ast.Tuple): # 处理解包赋值,确保左右值长度匹配 if isinstance(value, (list, tuple)) and len(value) == len(target.elts): for idx, elem_target in enumerate(target.elts): self._process_target(elem_target, value[idx]) elif isinstance(target, ast.Subscript): # 处理下标赋值,比如 lst[1] = 9 if isinstance(target.value, ast.Name): container_id = target.value.id index_val = evaluate_node(target.slice, self.env) self.assignments[(container_id, index_val)] = value # 更新环境中的容器对象 container = self.env.get(container_id) if container is not None and isinstance(index_val, int): container[index_val] = value self.env[container_id] = container def visit_For(self, node): """处理for循环,遍历迭代元素并处理循环体赋值""" iter_val = evaluate_node(node.iter, self.env) if not iter_val: return for item in iter_val: # 绑定循环变量到环境 if isinstance(node.target, ast.Name): self.env[node.target.id] = item # 处理循环体中的每个语句 for stmt in node.body: sub_visitor = AssignmentVisitor(self.env) sub_visitor.visit(stmt) self.assignments.update(sub_visitor.assignments) self.generic_visit(node) def parse_code_lines(code_str): """逐行解析代码字符串,返回每行的赋值结果列表""" env = {} results = [] lines = code_str.strip().split('\n') for line in lines: line = line.strip() if not line: results.append({}) continue try: tree = ast.parse(line, mode='exec') visitor = AssignmentVisitor(env) visitor.visit(tree) results.append(visitor.assignments) except SyntaxError: results.append({}) return results
测试示例
针对你提供的测试代码:
test_code = """a = 1 a, b = 2, 0 lst = [2, 3, b] lst[1] = 9""" output = parse_code_lines(test_code) for line_result in output: print(line_result)
输出结果:
{'a': 1} {'a': 2, 'b': 0} {'lst': [2, 3, 0]} {('lst', 1): 9}
扩展说明
- 复杂表达式支持:可以继续扩展
evaluate_node函数,支持更多AST节点类型(比如比较运算、函数调用等)。 - 作用域处理:如果需要处理函数内部的局部变量,可以在
visit_FunctionDef方法中创建局部环境字典,实现作用域隔离。 - 错误处理:可以添加更多异常捕获逻辑,比如变量未定义、赋值类型不匹配等情况的提示。
内容的提问来源于stack exchange,提问作者Sopan Thakre
相关产品推荐
相关产品推荐

