当前位置:首页 > Python > 正文

Python表达式求值算法详解(从零开始实现一个简易计算器)

在编程中,我们经常需要对数学表达式进行求值,比如 3 + 5 * 2。Python 本身提供了 eval() 函数来完成这项任务,但出于安全性和学习目的,理解其背后的原理非常重要。本教程将带你一步步实现一个简单的 Python表达式求值 算法,即使你是编程小白也能轻松上手!

Python表达式求值算法详解(从零开始实现一个简易计算器) Python表达式求值 Python语法解析 Python计算器实现 Python递归下降解析器 第1张

为什么不能直接用 eval()?

虽然 eval() 很方便,但它会执行任意 Python 代码,存在严重的安全隐患。例如:

# 危险示例!eval("__import__('os').system('rm -rf /')")  # 切勿尝试!

因此,自己实现一个只支持数学运算的 Python语法解析 器是更安全、更可控的选择。

表达式求值的基本思路

我们将采用“递归下降解析”(Recursive Descent Parsing)的方法,这是实现 Python递归下降解析器 的经典方式。核心思想是:根据运算符的优先级,将表达式分解为多个层级进行处理。

例如:3 + 5 * 2 应先计算乘法,再计算加法。我们可以定义两个层级:

  • term:处理乘法和除法(高优先级)
  • expr:处理加法和减法(低优先级)

完整代码实现

下面是一个支持 + - * / ( ) 和整数的简易表达式求值器:

class SimpleCalculator:    def __init__(self, expression):        self.tokens = self.tokenize(expression)        self.pos = 0    def tokenize(self, s):        """将字符串拆分为数字和操作符列表"""        tokens = []        i = 0        while i < len(s):            if s[i].isdigit():                num = ''                while i < len(s) and s[i].isdigit():                    num += s[i]                    i += 1                tokens.append(int(num))            elif s[i] in '+-*/()':                tokens.append(s[i])                i += 1            else:                i += 1  # 忽略空格等        return tokens    def peek(self):        if self.pos < len(self.tokens):            return self.tokens[self.pos]        return None    def consume(self):        token = self.peek()        self.pos += 1        return token    def parse_expr(self):        """处理加法和减法"""        result = self.parse_term()        while self.peek() in ('+', '-'):            op = self.consume()            right = self.parse_term()            if op == '+':                result += right            else:                result -= right        return result    def parse_term(self):        """处理乘法和除法"""        result = self.parse_factor()        while self.peek() in ('*', '/'):            op = self.consume()            right = self.parse_factor()            if op == '*':                result *= right            else:                result /= right        return result    def parse_factor(self):        """处理数字和括号"""        token = self.peek()        if isinstance(token, int):            return self.consume()        elif token == '(':            self.consume()  # 消耗 '('            result = self.parse_expr()            self.consume()  # 消耗 ')'            return result        else:            raise ValueError(f"Unexpected token: {token}")    def evaluate(self):        return self.parse_expr()# 使用示例if __name__ == "__main__":    expr = "3 + 5 * (2 - 1)"    calc = SimpleCalculator(expr)    print(f"{expr} = {calc.evaluate()}")  # 输出: 3 + 5 * (2 - 1) = 8

代码解析

1. tokenize:将输入字符串(如 "3+5*2")拆分为标记列表 [3, '+', 5, '*', 2]

2. parse_expr → parse_term → parse_factor:形成调用链,确保高优先级运算先执行。

3. **括号处理**:遇到 ( 时,递归调用 parse_expr(),实现子表达式求值。

扩展与应用

这个简易解析器可以作为 Python计算器实现 的基础。你可以进一步扩展它,支持:

  • 小数(如 3.14)
  • 变量(如 x + y)
  • 函数(如 sin(x))

掌握这一原理后,你不仅能写出更安全的表达式求值工具,还能深入理解编译器和解释器的工作机制!

总结

通过本教程,我们从零实现了一个支持基本四则运算和括号的表达式求值器。这不仅帮助你理解 Python表达式求值 的底层逻辑,也为后续学习更复杂的解析技术打下基础。记住:不要滥用 eval(),自己动手更安全、更有趣!