代码之家  ›  专栏  ›  技术社区  ›  Saketh

后缀表达式出现意外的Python错误。有人能解释我为什么会出现这个错误吗?

  •  -1
  • Saketh  · 技术社区  · 1 年前
    from collections import deque
    def postfixExpression(expression: str) -> int:
        if not expression:
            return -1
        expression_list = expression.split(" ")
        stack = deque()
        for ex in expression_list:
            print(ex, stack)
            try:
                stack.append(int(ex))
            except ValueError:
                b = stack.pop()
                a = stack.pop()
                switcher = {
                    "+" : a + b,
                    "-" : a - b,
                    "*" : a * b,
                    "/" : int(a / b),
                    "^" : a ** b,
                }
                if ex not in switcher.keys():
                    raise ValueError(f"Wrong expression-> {ex}")
                else:
                    stack.append(switcher.get(ex))
        return stack.pop()
    
    expression = "2 3 7 - 7 + 9 7 2 + - * *"
    print(f"\nResult {postfixExpression(expression)}")
    

    以上是python中的Postfix评估程序。它适用于大多数情况。

    但当我使用输入时 "2 3 7 - 7 + 9 7 2 + - * *" ,它在给予 ZeroDivisionError ,甚至认为我没有使用除法( / )输入中。

    错误消息:

    $ python temp/temp.py 
    4 deque([])
    6 deque([4])
    * deque([4, 6])
    2 deque([24])
    1 deque([24, 2])
    - deque([24, 2, 1])
    + deque([24, 1])
    7 deque([25])
    7 deque([25, 7])
    + deque([25, 7, 7])
    7 deque([25, 14])
    6 deque([25, 14, 7])
    + deque([25, 14, 7, 6])
    * deque([25, 14, 13])
    * deque([25, 182])
    3 deque([4550])
    7 deque([4550, 3])
    - deque([4550, 3, 7])
    7 deque([4550, -4])
    + deque([4550, -4, 7])
    9 deque([4550, 3])
    7 deque([4550, 3, 9])
    2 deque([4550, 3, 9, 7])
    + deque([4550, 3, 9, 7, 2])
    - deque([4550, 3, 9, 9])
    * deque([4550, 3, 0])
    Traceback (most recent call last):
      File "C:\Users\...\temp.py", line 11, in postfixExpression
        stack.append(int(ex))
    ValueError: invalid literal for int() with base 10: '*'
    
    During handling of the above exception, another exception occurred:
    
    Traceback (most recent call last):
      File "C:\Users\...\temp.py", line 52, in main
        print(f"\nresult {postfixExpression(expression)}")
      File "C:\Users\...\temp.py", line 19, in postfixExpression
        "/" : int(a / b),
    ZeroDivisionError: division by zero
    

    当我发表评论时 "/" : int(a / b), 切换器dict中的行给出了预期的答案,即0。

    有人能解释我为什么会出现这个错误(main)以及如何解决它吗?

    2 回复  |  直到 1 年前
        1
  •  1
  •   lxop    1 年前

    问题是你正在评估 全部的 的操作 switcher 词典因此,无论代码遇到哪种运算符,它都会计算堆栈顶部两个值的和、差、积和商。然后,它查看操作符,以决定实际使用哪一个。在这种情况下,您的 b 值为零,所以它确实试图除以零。

    有多种方法可以解决此问题,包括(但不限于):

    • 使用 lambda 中的函数 切换器 字典,并且只调用所需的
                switcher = {
                    "+" : lambda: a + b,
                    "-" : lambda: a - b,
                    "*" : lambda: a * b,
                    "/" : lambda: int(a / b),
                    "^" : lambda: a ** b,
                }
                if ex not in switcher:
                    raise ValueError(f"Wrong expression-> {ex}")
                else:
                    stack.append(switcher[ex]())  # <- note the added () here
    
    • 只需使用 match 语句直接在代码中计算适当的值,而不是使用字典(这需要Python 3.10+)
        match ex:
            case "+":
                val = a + b
            case "-":
                val = a - b
            case "*":
                val = a * b
            case "/":
                val = int(a / b)
            case "^":
                val = a ** b
            case _:
                raise ValueError(f"Wrong expression-> {ex}")
        stack.append(val)
    
    • 使用 if - elif 链直接在代码中计算适当的值,而不是使用字典
        if ex == "+":
            val = a + b
        elif ex == "-":
            val = a - b
        elif ex == "*":
            val = a * b
        elif ex == "/":
            val = int(a / b)
        elif ex == "^":
            val = a ** b
        else:
            raise ValueError(f"Wrong expression-> {ex}")
        stack.append(val)
    

    在任何情况下,我都建议您将计算操作拉到它自己的函数中,而不是将其嵌入到循环的中间。有点像

    def calculate_value(op, a, b):
        ...  # Something based on what I've shown above
    
    
    def postfixExpression(expression: str) -> int:
        if not expression:
            return -1
        expression_list = expression.split(" ")
        stack = deque()
        for ex in expression_list:
            print(ex, stack)
            try:
                stack.append(int(ex))
            except ValueError:
                b = stack.pop()
                a = stack.pop()
                stack.append(calculate_value(ex, a, b))
        return stack.pop()
    


    应要求:测试代码使用 λ 功能:

    from collections import deque
    def postfixExpression(expression: str) -> int:
        if not expression:
            return -1
        expression_list = expression.split(" ")
        stack = deque()
        for ex in expression_list:
            print(ex, stack)
            try:
                stack.append(int(ex))
            except ValueError:
                b = stack.pop()
                a = stack.pop()
                switcher = {
                    "+" : lambda: a + b,
                    "-" : lambda: a - b,
                    "*" : lambda: a * b,
                    "/" : lambda: int(a / b),
                    "^" : lambda: a ** b,
                }
                if ex not in switcher.keys():
                    raise ValueError(f"Wrong expression-> {ex}")
                else:
                    stack.append(switcher.get(ex)())
        return stack.pop()
    
    expression = "2 3 7 - 7 + 9 7 2 + - * *"
    print(f"\nResult {postfixExpression(expression)}")
    

    带输出

    2 deque([])
    3 deque([2])
    7 deque([2, 3])
    - deque([2, 3, 7])
    7 deque([2, -4])
    + deque([2, -4, 7])
    9 deque([2, 3])
    7 deque([2, 3, 9])
    2 deque([2, 3, 9, 7])
    + deque([2, 3, 9, 7, 2])
    - deque([2, 3, 9, 9])
    * deque([2, 3, 0])
    * deque([2, 0])
    
    Result 0
    
        2
  •  1
  •   OM222O    1 年前

    我相信这就是你真正想要实现的目标,但很难说,因为你没有提供一个你手工解决的例子或预期的输出:

    from collections import deque
    
    switcher = {
        "+" : lambda a,b:a + b,
        "-" : lambda a,b:a - b,
        "*" : lambda a,b:a * b,
        "/" : lambda a,b:a // b,
        "^" : lambda a,b:a ** b,
    }
    
    def postfixExpression(expression: str) -> int:
        if not expression:
            return -1
        expression_list = expression.split(" ")
        stack = deque()
        for ex in expression_list:
            print(ex, stack)
            if ex.isnumeric():
                stack.append(int(ex))
            elif ex in switcher:
                stack.append(switcher[ex](stack.pop(),stack.pop()))
            else:
                raise ValueError(f"Wrong expression-> {ex}")
        return stack.pop()
    
    expression = "2 3 7 - 7 + 9 7 2 + - * *"
    print(f"\nResult {postfixExpression(expression)}")
    

    编辑:只是提供的解决方案之间的快速比较,以下是代码:

    from collections import deque
    
    def postfixExpression_OP_LAMBDA(expression: str) -> int:
        if not expression:
            return -1
        expression_list = expression.split(" ")
        stack = deque()
        for ex in expression_list:
            try:
                stack.append(int(ex))
            except ValueError:
                b = stack.pop()
                a = stack.pop()
                switcher = {
                    "+" : lambda a,b: a + b,
                    "-" : lambda a,b: a - b,
                    "*" : lambda a,b: a * b,
                    "/" : lambda a,b: int(a / b),
                    "^" : lambda a,b: a ** b,
                }
                if ex not in switcher.keys():
                    raise ValueError(f"Wrong expression-> {ex}")
                else:
                    stack.append(switcher.get(ex)(a,b))
        return stack.pop()
    
    def postfixExpression_MATCH(expression: str) -> int:
        if not expression:
            return -1
        expression_list = expression.split(" ")
        stack = deque()
        for ex in expression_list:
            try:
                stack.append(int(ex))
            except ValueError:
                b = stack.pop()
                a = stack.pop()
                match ex:
                    case "+":
                        val = a + b
                    case "-":
                        val = a - b
                    case "*":
                        val = a * b
                    case "/":
                        val = int(a / b)
                    case "^":
                        val = a ** b
                    case _:
                        raise ValueError(f"Wrong expression-> {ex}")
                stack.append(val)
        return stack.pop()
    
    switcher_ = {
        "+" : lambda a,b:a + b,
        "-" : lambda a,b:a - b,
        "*" : lambda a,b:a * b,
        "/" : lambda a,b:a // b,
        "^" : lambda a,b:a ** b,
    }
    
    def postfixExpression_OM(expression: str) -> int:
        if not expression:
            return -1
        expression_list = expression.split(" ")
        stack = deque()
        for ex in expression_list:
            if ex.isnumeric():
                stack.append(int(ex))
            elif ex in switcher_:
                stack.append(switcher_[ex](stack.pop(),stack.pop()))
            else:
                raise ValueError(f"Wrong expression-> {ex}")
        return stack.pop()
    
    expression = "2 3 7 - 7 + 9 7 2 + - * *"
    

    以及用于比较的快速基准: enter image description here 我的解决方案是快3到4倍,这取决于你所做的和正确使用Lambda。如果重命名a或b,@lxop提供的解决方案将失败,因为他依赖于极差的变量作用域(此处有更多详细信息: https://www.youtube.com/watch?v=fZE6ZWde-Os )。 enter image description here