Python中的计算器
我正在尝试制作一个计算器,可以解决包含基本四个运算符的表达式,比如 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 个回答
在你的代码中,你没有对 s.partition(c)
的结果进行任何判断。所以即使这个分割的结果是 ('任何东西', '', '')
,你还是会在第一个条件下进行递归。
编辑过
你现在做错的主要一点是,你在检查变量 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
你在处理输入字符串时,不管怎样都会进行分割,从来不检查操作符是否存在。.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))