后缀表达式出现意外的 Python ZeroDivisionError,当所述键时,值对永远不会被调用。谁能解释一下为什么我会收到此错误?

问题描述 投票:0回答:2
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),
行时,它给出了预期的答案,即0。

任何人都可以解释为什么我会收到此错误(主要)以及如何解决它?

python stack
2个回答
1
投票

问题是您在设置 switcher 字典时正在评估

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

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

  • 使用
    lambda
    字典中的
    switcher
    函数,并且只调用需要的函数
            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()


根据要求:使用

lambda
函数的测试代码:

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

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 + - * *"

以及一个快速比较基准: 我的解决方案速度快 3 到 4 倍,具体取决于您的操作和正确使用 lambda。如果您重命名 a 或 b,@lxop 提供的解决方案将会失败,因为他依赖于极其糟糕的变量范围(更多详细信息:https://www.youtube.com/watch?v=fZE6ZWde-Os)。

© www.soinside.com 2019 - 2024. All rights reserved.