不能直接用eval()解析算术表达式,因其存在安全风险(如执行恶意系统命令)、不支持自定义函数/变量、无法控制错误提示和运算规则。

为什么不能直接用 eval() 解析算术表达式
因为不安全、不可控、无法定制错误提示和运算规则。比如用户输入 "__import__('os').system('rm -rf /')" 会直接执行系统命令;又或者需要支持自定义函数(如 sin(3.14))、变量(如 x + 2 * y),eval() 就束手无策。
双栈结构的核心分工:操作符栈 vs 操作数栈
双栈不是为了炫技,而是自然对应表达式解析的两个维度:数值怎么存、运算怎么调度。操作数栈(nums)只压入数字或子表达式结果;操作符栈(ops)只压入 '+'、'-'、'*'、'/'、'(',遇到 ')' 就触发计算直到弹出匹配的 '('。
关键细节:
- 遇到数字立即转为
float或int后压入nums - 遇到操作符时,先检查
ops栈顶是否为更高优先级的运算符(如'*'或'/'),是则先计算再压入当前操作符 -
'('无条件压栈;')'不压栈,而是持续pop并计算,直到ops[-1] == '(',然后把这对括号都丢掉 - 一元负号(如
-5或3 * -2)需在词法阶段识别为['3', '*', 'NEG', '2'],否则会被误判为二元减法
处理括号嵌套和右结合运算符的实际难点
双栈本身不天然支持右结合(如幂运算 **),若强行加入,需修改优先级判断逻辑:对右结合运算符,仅当栈顶是「严格更高」优先级时才计算,而不是「大于等于」。但 Python 原生算术表达式中只有 ** 是右结合,其余都是左结合——所以多数场景下,你其实不需要改。
立即学习“Python免费学习笔记(深入)”;
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
括号嵌套的坑在于空括号或非法位置,例如 "2 + () * 3"。双栈不会主动报错,必须在词法分析阶段过滤掉空 token,或在遇到 ')' 时检查 nums 是否至少有两个数(否则说明缺少操作数)。
示例片段(简化版核心逻辑):
while ops and ops[-1] != '(' and precedence[ops[-1]] >= precedence[c]:
b, a = nums.pop(), nums.pop()
nums.append(apply_op(a, b, ops.pop()))
ops.append(c)要不要自己写词法分析器?还是用 re.findall() 糊弄过去
简单场景(仅数字、四则、括号)用正则够用:re.findall(r'\d+\.?\d*|[+\-*/()]', s)。但它无法区分减号和负号,也不能处理科学计数法(如 1e-5)或函数调用。
真实项目里,一旦出现 max(1,2)+sin(x)**2 这类需求,就必须上真正的 tokenizer:按字符扫描,状态机驱动,识别标识符、数字字面量、括号、操作符,并预处理一元符号。这不是过度设计——双栈只是语法分析层,它依赖上游提供干净、无歧义的 token 流。
容易被忽略的一点:浮点数解析要用 float(token) 而非 int(token),否则 "1.5 + 2" 会因 int("1.5") 报错;但也要小心 float("inf") 这类非法输入,需加 try/except。

















