在python中评估后缀?

在python中评估后缀?,python,postfix-notation,Python,Postfix Notation,我想写一个函数来计算作为列表传递的后缀表达式。到目前为止,我得到了: def evalPostfix(text): s = Stack() for symbol in text: if symbol in "0123456789": s.push(int(symbol)) if not s.is_empty(): if symbol == "+": plus = s.p

我想写一个函数来计算作为列表传递的后缀表达式。到目前为止,我得到了:

def evalPostfix(text):
    s = Stack()
    for symbol in text:
        if symbol in "0123456789":
            s.push(int(symbol))
        if not s.is_empty():
            if symbol == "+":
                plus = s.pop() + s.pop()
            if symbol == "-":
                plus = s.pop() - s.pop()
            if symbol == "*":
                plus = s.pop() * s.pop()
            if symbol == "/":
                plus = s.pop() / s.pop()

但我认为我的方法是错误的。帮助?

您有一些问题:

  • 遇到运算符后,将丢弃该值。要解决此问题,必须将任何运算符的结果推回到堆栈,然后继续下一步
  • 当遇到一个数字时,您不会跳过其余的逻辑(这不会使您的代码返回错误的答案,但仍然不是很聪明)
  • 您的函数不返回任何内容
  • 像这样的方法应该会奏效:

    def eval_postfix(text):
        s = list()
        for symbol in text:
            if symbol in "0123456789":
                s.append(int(symbol))
    
            plus = None
            elif not s.is_empty():
                if symbol == "+":
                    plus = s.pop() + s.pop()
                elif symbol == "-":
                    plus = s.pop() - s.pop()
                elif symbol == "*":
                    plus = s.pop() * s.pop()
                elif symbol == "/":
                    plus = s.pop() / s.pop()
            if plus is not None:
                s.append(plus)
            else:
                 raise Exception("unknown value %s"%symbol)
        return s.pop()
    

    这里有一个可能对您有用的解决方案。我试着尽可能少地修改你的代码

    更改#1:与其检查
    symbol
    是否介于0和9之间,不如尝试将
    symbol
    (以
    字符串开始)转换为
    int
    。如果成功,您可以将
    symbol
    视为操作数。(这允许您的代码处理多位数。)

    更改#2:如果
    文本
    中出现非数字、非运算符,则引发错误。(你不希望里面还有其他东西。)

    更改#3:使用
    eval
    而不是写出每个运算符<代码>评估
    带来了很多安全问题,但我认为在这里,因为我们确保所有东西都是数字或操作员,所以我们没事

    更改#4:将中间结果推入堆栈

    更改#5:在列表用尽后返回
    s.pop()
    。您可能需要添加一行,确认此时
    s
    仅包含一个值

    注意:请注意,此代码假定每次遇到运算符时,
    s
    将包含两个值。如果另一对
    try
    /
    语句出现错误,您可能希望捕获该错误

    def evalPostfix(text):
        s = Stack()
        for symbol in text:
            try:
                result = int(symbol)
            except ValueError:
                if symbol not in '+-*/':
                    raise ValueError('text must contain only numbers and operators')
                result = eval('%d %s %d' % (s.pop(), symbol, s.pop()))
            s.push(result)
        return s.pop() 
    

    Hosane为你的问题提供了一个非常详细的答案,但是我认为我看到了一个错误,尽管我承认我不是这方面的专家

    因为你用的是流行音乐,所以你的计算是这样的。 (堆栈中的最后一个数字)(运算符)(堆栈中的第二个最后一个数字) 例如,如果列表中有[“3”、“2”、“+”],则得到3+2

    这对于加法或乘法都很好,但是如果你使用除法或减法,这将导致错误的答案。例如,postfix中的(3-2)将是[3,2,-]。您的代码会将其计算为(2-3),而它应该是(3-2)

    所以你应该改变除法和减法,如果情况是

    elif symbol=="-":
            s.append(-stack.pop() + stack.pop())
    elif symbol=="/":
            s.append(1/stack.pop() * stack.pop())
    

    翻译K&R C示例的工作代码

    def eval_postfix(text):
    
        stack = []
        tokens = text.split(" ")
    
        for token in tokens:
    
            if token.strip() == '':
                continue 
    
            elif token == "+":
                stack.append(stack.pop() + stack.pop())
    
            elif token == "-":
                op2 = stack.pop() 
                stack.append(stack.pop() - op2)
    
            elif token == '*':
                stack.append(stack.pop() * stack.pop())
    
            elif token == '/':
                op2 = stack.pop()
                if op2 != 0.0:
                    stack.append(stack.pop() / op2)
                else:
                    raise ValueError("division by zero found!")
    
            elif (is_number(token)):
                    stack.append(float(token))
    
            else:
                raise ValueError("unknown token {0}".format(token))
    
    
        return stack.pop()
    

    现在这个函数不返回任何内容。什么是
    堆栈
    推送
    做什么?为什么您认为这种方法是错误的?@dbliss我使用的是堆栈(抽象数据类型)并且有一个类使用push和pop方法从堆栈中添加/删除元素。@Stefan Pochmann主要是因为我不确定如何返回正确的值。如果只有两个操作数,并且它们始终是单位数,那么我认为您现在的操作数是有效的。只需返回
    plus
    。很好。你的回答让我意识到中间结果应该被推到堆栈上。我的答案正确吗?您是否切换到
    列表
    ,以便您和其他人可以测试它?您可以使用
    类堆栈(list):push=list.append
    。只是说因为我喜欢你尽量不做太多的改变。是的,但基本上我在过去几年一直使用列表作为堆栈。但是,您的建议使代码更具可读性。:)我认为OP的
    push
    可能会像
    append
    那样将项目添加到堆栈的前端,而不是末尾。OP没有指定,所以我们不能确定。是的,push会将项目添加到列表的前面,我使用堆栈是因为您无法将append方法用于堆栈,但是在列表上使用append方法也可以,非常感谢@HosaneI我认为“我已尝试尽可能少地更改您的代码”是一个谎言:-PHa,是的,这是我一开始的目标,不管怎样,我真的不喜欢例外的方法。您还可以使用symbol.isdigit()方法来确定是否只讨论单字符数字(这里就是这种情况)。
    eval
    在这里,因为
    eval
    在任何地方都是一个坏主意。而且,即使
    eval
    是合理的,使用Python的解析器计算算术也完全没有从零开始编写表达式计算器的意义。