Python中的计算器

1 投票
9 回答
4883 浏览
提问于 2025-04-17 17:17

我正在尝试制作一个计算器,可以解决包含基本四个运算符的表达式,比如 1+2*3-4/5,但它并没有正常工作,我不知道哪里出了问题。请检查我的代码。

当我运行它时,在第8行 return ret(parts[0]) * ret(parts[2]) 出现了无数个错误。

这是我的代码:

def ret(s):
    s = str(s)
    if s.isdigit():
        return float(s)
    for c in ('*','/','+','-'):
        parts = s.partition(c)
        if c == '*':
            return ret(parts[0]) * ret(parts[2])
        elif c == '/':
            return ret(parts[0]) / ret(parts[2])
        elif c == '+':
            return ret(parts[0]) + ret(parts[2])
        elif c == '-':
            return ret(parts[0]) - ret(parts[2])
print(ret('1+2'))

而错误的追踪信息最后是:

  File "C:\Python33\calc.py", line 8, in ret
    return ret(parts[0]) * ret(parts[2])
  File "C:\Python33\calc.py", line 2, in ret
    s = str(s)
RuntimeError: maximum recursion depth exceeded while calling a Python object

9 个回答

0

在你的代码中,你没有对 s.partition(c) 的结果进行任何判断。所以即使这个分割的结果是 ('任何东西', '', ''),你还是会在第一个条件下进行递归。

编辑过

1

你现在做错的主要一点是,你在检查变量 c 的值,而不是分区操作符。你还可以通过使用左边和右边来解包 s.partition 的结果,这样会让事情变得简单一些。

def ret(s):
    s = str(s)
    if s.isdigit():
        return float(s)
    for c in ('-','+','*','/'):
        left, op, right = s.partition(c)
        if op == '*':
            return ret(left) * ret(right)
        elif op == '/':
            return ret(left) / ret(right)
        elif op == '+':
            return ret(left) + ret(right)
        elif op == '-':
            return ret(left) - ret(right)
print(ret('1+2'))

另外,你需要调整一下操作的顺序,因为你想先进行加法和减法,然后再进行乘法和除法。

我的意思是,如果你有一个表达式,比如 4+4*3,你应该把它分成

ret(4) + ret(4 * 3)

由于这是一个递归调用,你希望优先级最高的操作符在调用栈的最后,这样在函数返回时它们会被优先执行。

举个例子:

print(ret('1+2*6'))
print(ret('3*8+6/2'))

输出

13.0
27.0
1

你在处理输入字符串时,不管怎样都会进行分割,从来不检查操作符是否存在。.partition() 如果分割字符不在输入中,就会返回空字符串:

 >>> '1+1'.partition('*')
 ('1+1', '', '')

所以你会调用 s.partition('*'),但从来不检查是否真的有这个操作符,这样就会无条件地调用 ret()。无论 * 是否在 s 中,你都会 总是 调用 ret(parts[0]) * ret(parts[2])

解决这个问题的方法是要么先检查操作符是否存在,要么检查 .partition() 的返回值。后者可能更简单:

for c in ('+','-','*','/'):
    parts = s.partition(c)
    if parts[1] == '*':
        return ret(parts[0]) * ret(parts[2])
    elif parts[1] == '/':
        return ret(parts[0]) / ret(parts[2])
    elif parts[1] == '+':
        return ret(parts[0]) + ret(parts[2])
    elif parts[1] == '-':
        return ret(parts[0]) - ret(parts[2])

注意我把操作符的顺序反过来了;是的,乘法和除法需要在加法和减法之前进行,但在这里你是以 反向 的方式处理的;把表达式拆分成更小的部分,然后在处理完子表达式后再应用操作。

你可以使用赋值解包,把 .partition() 返回的三个值赋给更容易理解的名字:

for c in ('+','-','*','/'):
    left, operator, right = s.partition(c)
    if operator == '*':
        return ret(left) * ret(right)
    elif operator == '/':
        return ret(left) / ret(right)
    elif operator == '+':
        return ret(left) + ret(right)
    elif operator == '-':
        return ret(left) - ret(right)

接下来,你可以通过使用 operator 模块简化 这一切,这个模块里有一些函数,可以执行和你的算术操作相同的操作。使用映射应该可以做到:

import operator
ops = {'*': operator.mul, '/': operator.div, '+': operator.add, '-': operator.sub}

for c in ('+','-','*','/'):
    left, operator, right = s.partition(c)
    if operator in ops:
        return ops[operator](ret(left), ret(right))

撰写回答