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)}")
Above is a Postfix Evaluation program in python. It's working for most case.
But when I used input "2 3 7 - 7 + 9 7 2 + - * *"
, it's giving ZeroDivisionError
, even thought I didn't use divide(/
) in input.
Error message:
$ 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
When I comment "/" : int(a / b),
line in switcher dict it's giving expected answer i.e 0.
Can anyone explain why I am getting this error (main) and how to solve it?
The problem is that you are evaluating all of the operations at the time you set up your switcher
dictionary. So regardless of which operator your code encounters, it calculates the sum, difference, product, and quotient of the two values at the top of the stack. Then it looks at the operator to decide which one to actually use. In this case, your b
value is zero, so it is indeed trying to divide by zero.
There are a number of ways that you could fix this, including (but not limited to):
lambda
functions in your switcher
dictionary, and only call the one that is needed 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
statement to calculate the appropriate value directly in the code rather than using a dictionary (this requires 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
chain to calculate the appropriate value directly in the code rather than using a dictionary 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)
In any case, I would recommend that you pull the calculation operation into a function of its own instead of having it embedded in the middle of your loop. Something like
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()
On request: the tested code using lambda
functions:
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)}")
with output
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