如何拼接计算Python表达式列表并修复ast方法无法处理多位数的问题
问题原因
- 原有逐字符拆分表达式为列表的逻辑不适用多位数场景:输入
"10+20"会被拆为['1','0','+','2','0'],无法识别连续数字为完整数值。 - 现有ast解析代码不支持多位数的核心原因是Python3.8及以上版本废弃了
ast.Num节点,所有数字常量会被解析为ast.Constant节点,原有判断逻辑未兼容该类型,运行时会直接抛出异常。
解决方案
方案1:直接处理原表达式字符串(无需拆分列表,兼容多位数)
仅需要在原有ast解析逻辑中新增ast.Constant节点的兼容判断即可,修改后代码如下:
import ast import operator as op operators = { ast.Add: op.add, ast.Sub: op.sub, ast.Mult: op.mul, ast.Div: op.truediv, ast.Pow: op.pow, ast.BitXor: op.xor, ast.USub: op.neg } def eval_expr(expr): return eval_(ast.parse(expr, mode='eval').body) def eval_(node): # 兼容高低版本Python的数字节点 if isinstance(node, ast.Num): return node.n elif isinstance(node, ast.Constant): return node.value elif isinstance(node, ast.BinOp): return operators[type(node.op)](eval_(node.left), eval_(node.right)) elif isinstance(node, ast.UnaryOp): return operators[type(node.op)](eval_(node.operand)) else: raise TypeError(f"不支持的运算节点:{type(node)}") # 测试用例 expr = "10+20*3" # 输出要求格式 print(f"{list(expr)} = {eval_expr(expr)}") # 运行输出:['1', '0', '+', '2', '0', '*', '3'] = 70
注意:该方案仅适合处理可控的内部输入表达式,如果需要处理外部用户提交的不可信表达式,需要额外增加节点类型白名单校验,避免代码注入风险。
方案2:需要从token列表计算的场景,先修正拆分逻辑
如果必须先把表达式拆分为含完整多位数的token列表,先替换原有逐字符拆分的代码:
def split_to_tokens(expr_str): tokens = [] num_buf = "" for c in expr_str: # 连续数字/小数点归入数值缓存 if c.isdigit() or c == ".": num_buf += c else: # 遇到运算符先把缓存的数值存入列表 if num_buf: tokens.append(num_buf) num_buf = "" tokens.append(c) # 处理末尾剩余的数值 if num_buf: tokens.append(num_buf) return tokens # 测试多位数拆分 print(split_to_tokens("10+20*3")) # 输出:['10', '+', '20', '*', '3']
拿到正确的token列表后拼接为字符串传入eval_expr即可得到结果:
tokens = split_to_tokens("10+20*3") result = eval_expr("".join(tokens)) print(f"{tokens} = {result}") # 输出:['10', '+', '20', '*', '3'] = 70
内容的提问来源于stack exchange,提问作者Jones
相关产品推荐
相关产品推荐

