我正在用Python编写一个计算器(作为练习),有一点我想知道.
程序将输入拆分为数字和运算符列表.然后计算结果:
import operator
ops = {'+' : operator.add, # operators and corresponding functions
'-' : operator.sub,
'*' : operator.mul,
'/' : operator.truediv,
'%' : operator.mod}
precedence = [['*', '/', '%'], ['+', '-']] # order of precedence for operators
def evaluate(exp):
for oplist in precedence: # search for operators first in order of precedence
for op in exp: # then from left to right
if op in oplist:
index = exp.index(op)
result = ops[op](exp[index - 1], exp[index + 1])
# compute the result of the operation
exp[index - 1:index + 2] = [result]
# replace operation and operands with result
return exp[0]
# for example,
evaluate([2, '+', 3, '+', 4, '+', 5])
# should return 14
此函数按优先级递减顺序查看算术运算符列表,然后从左到右查找,当找到这样的运算符时,它会调用相邻列表元素(操作数)上的相应函数,并替换运算符和操作数.列出操作的结果.一旦执行了所有操作,列表将包含单个元素 – 计算结果.
但是,此功能的行为方式不符合预期.问题(我认为)是这个函数在迭代它时修改列表(通过分配给切片).我已经找到了这个问题here的解决方案(通过每次修改列表时重新启动内部for循环),但是给出解决方案的人似乎认为通常应该有更好的方法来完成所需的任何操作. .
我想知道是否有更好的方法来实现这个算法,避免了奇怪的“重启循环”.
谢谢你的任何想法!
解决方法:
我想我会采用不同的方式,并使用递归函数.弹出操作并将其替换为评估结果.
import operator
ops = {
'+' : operator.add,
'-' : operator.sub,
'*' : operator.mul,
'/' : operator.truediv,
'%' : operator.mod,
}
precedence = [
set(['*', '/', '%']),
set(['+', '-']),
]
def evaluate(expr):
# if len == 3 then just return result of expression
if len(expr) == 3:
l, op, r = expr
return ops[op](l, r)
else:
for op_list in precedence:
for op in expr:
if op in op_list:
# find index of first operation
idx = expr.index(op)-1
# pop off and evaluate first matching operation in expr
result = evaluate([expr.pop(idx) for i in range(3)])
# insert result back into expr
expr.insert(idx, result)
return evaluate(expr)