You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从Python代码字符串中提取已定义/更新变量的标识与对应值?

解决方案:用AST逐行解析Python代码中的赋值操作

要实现逐行解析Python代码字符串、提取标识符及其赋值的需求,你可以基于ast模块构建针对性的节点访问器,同时维护一个环境字典来跟踪变量的当前值。以下是具体实现步骤和代码:

核心思路

  1. 逐行解析:将代码按行分割,每行单独解析为AST。
  2. 节点求值:编写函数将AST节点转换为实际Python值,利用环境字典解析变量引用。
  3. 赋值处理:通过ast.NodeVisitor子类,针对性处理不同类型的赋值节点(普通变量、解包赋值、下标赋值),记录赋值关系并更新环境。
  4. 循环支持:扩展访问器处理循环节点,遍历迭代元素并处理循环体中的赋值。

完整代码实现

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 05:16:05