I learn about Reverse Polish Notation (:RPN).
I want to calculate Numerical formula by using RPN.
I managed to write following Program.
At a glance, this code work properly.
But, when I submitted this code to Programming Contest Site, (
http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=0109
) I got Wrong Answer.
What is wrong with my code?
# coding: utf-8
# Convert String to List
def String2List(s):
L = []
flag = True
l = len(s)
for i in range(l):
if s[i].isdigit() and flag:
t = ""
j = 0
while s[i+j].isdigit():
t += s[i+j]
if i+j == l-1:
break
j += 1
L.append(t)
flag = False
elif not s[i].isdigit():
L.append(s[i])
flag = True
return L
# generate Reverse Polish Notation
def RPN_list(L):
S, L2 = [], []
table = {"*": 1, "/": 1, "+": 0, "-": 0, "(": -1, ")": -1}
for i in L:
if i.isdigit():
L2.append(i)
elif i == "(":
S.append(i)
elif i == ")":
while S[-1] != "(":
L2.append(S.pop())
S.pop()
else:
if len(S) != 0 and (table[S[-1]] >= table[i]):
L2.append(S.pop())
S.append(i)
while len(S) != 0:
L2.append(S.pop())
return L2
# calculate Reverse Polish Notation
def RPN_cul(L):
St = []
for i in L:
if i == '+':
St.append(int(St.pop()) + int(St.pop()))
elif i == '-':
St.append(-int(St.pop()) + int(St.pop()))
elif i == '*':
St.append(int(St.pop()) * int(St.pop()))
elif i == '/':
a = int(St.pop())
b = float(St.pop())
St.append(b/a)
else:
St.append(i)
return St[0]
N = int(raw_input())
for i in range(N):
s = raw_input()
L = String2List(s[:-1])
L = RPN_list(L)
print int(RPN_cul(L))
Result
$ python reverse_polish_notation.py
2
4-2*3=
-2
4*(8+4+3)=
60
when I fixed as follows, It was accepted. Thanks to help me.
Before:
def RPN_list(L):
...
if len(S) != 0 and (table[S[-1]] >= table[i]):
L2.append(S.pop())
S.append(i)
...
After:
def RPN_list(L):
...
while len(S) != 0 and (table[S[-1]] >= table[i]):
L2.append(S.pop())
S.append(i)
...
polish_str="123*+4-"
#scan from left to right once you got the operator make the operation save the result again perform the operation
#result=3
polish_list=[]
for i in polish_str:
polish_list.append(i)
print(polish_list)
####
temp=[]
operator=['*',"+","/","-"]
def operation(o,a,b):
if o=="+":
result=a+b
if o=="-":
result=a-b
if o=="*":
result=a*b
if o=="/":
result=a/b
return result
for i,v in enumerate(polish_list):
if v in operator:
print(temp)
leng=len(temp)
arg1=temp.pop()
print("arg1==>",arg1)
arg2=temp.pop()
print("arg2==>",arg2)
result=operation(v,arg1,arg2)
print("result==>",result)
temp.append(result)
print("temp in iteration==>",temp)
else:
temp.append(i)
print("***final temp***",temp)
Related
I'm trying for a while now to submit my solution to the following problem on Kattis: I can guess the data structure!. However, I keep getting a runtime error; I cannot think of anywhere it can go wrong since it works with all my input. Here is my solution:
import heapq, sys
def throwin(q,s,h,x, results):
if results[0]:
q.append(x)
if results[1]:
s.append(x)
if results[2]:
heapq.heappush(h, -x)
return (q,s ,h )
def printstructures(l):
for j in l:
if j[0] and j[1] or j[0] and j[2] or j[1] and j[2]:
print("not sure")
elif not j[0] and not j[1] and not j[2]:
print("impossible")
elif j[0]:
print("queue")
elif j[1]:
print("stack")
else:
print("priority queue")
def main():
results_global = []
stackops = []
current = []
while True:
try:
line = input()
if len(line) == 1:
if len(current) != 0:
stackops.append(current)
current = []
else:
current.append(tuple(map(int, line.split(" "))))
except EOFError:
break
stackops.append(current)
for op in stackops:
q,s,h = [],[],[]
heapq._heapify_max(h)
results = [True, True, True]
for i in range(len(op)):
o, x = op[i]
if o == 1:
q,s,h = throwin(q,s,h,x, results)
else:
if len(q) == 0 or q[0] != x:
results[0] = False
else:
q.pop(0)
if len(s) == 0 or s[-1] != x:
results[1] = False
else:
s.pop()
if len(h) == 0 or h[0] != -x :
results[2] = False
else:
heapq.heappop(h)
if i == len(op)-1:
results_global.append(results)
printstructures(results_global)
if __name__ == "__main__":
main()
I was wondering if anyone can give me a push in the right direction and point out where my thinking is wrong or if I made a mistake somewhere I overlooked.
I had the same runtime-error problem for this question, I think it has something to do with python input/output EOFError. I couldn't figure the specific error out but I just put a try/except pass over my entire program and kattis accepted the solution.
import sys
try:
def solve(n):
stack = []
queue = []
priority_queue = []
type_ds = [True, True, True]
for i in range(n):
command, element = map(int, input().split())
if command == 1:
if type_ds[0] != False:
stack.append(element)
if type_ds[1] != False:
queue.append(element)
if type_ds[2] != False:
priority_queue.append(element)
elif command == 2:
if type_ds[0] != False:
if len(stack) == 0:
return "impossible"
if element != stack.pop():
type_ds[0] = False
stack.clear()
if type_ds[1] != False:
if len(queue) == 0:
return "impossible"
if element != queue.pop(0):
type_ds[1] = False
queue.clear()
if type_ds[2] != False:
if len(priority_queue) == 0:
return "impossible"
priority_queue.sort(reverse=True)
if element != priority_queue.pop(0):
type_ds[2] = False
priority_queue.clear()
if type_ds.count(True) > 1:
return "not sure"
elif type_ds.count(True) == 0:
return "impossible"
else:
if type_ds[0] == True:
return "stack"
elif type_ds[1] == True:
return "queue"
else:
return "priority queue"
for line in sys.stdin:
if line.strip() == "":
break
n = int(line.strip())
print(solve(n))
except:
pass
Are you sure you're breaking out of the while loop? Is it running correctly on your computer? In competitive programming, with time limits, it's normally not a good idea to use try/except statements, it's slowing down the script by a lot.
I am trying to convert the code here http://www.geeksforgeeks.org/expression-evaluation/ to python. However, I am running into some trouble and can't figure out.
class evaluateString:
def evalString(self,expression):
valueStack = []
opStack = []
i=0
while(i<len(expression)):
if(expression[i] == ' '):
continue
if(expression[i]>='0' and expression[i] <= '9'):
charNumber = [] #for storing number
while(i<len(expression) and expression[i]>='0' and expression[i] <= '9'):
charNumber.append(expression[i])
i+=1
valueStack.append(int(''.join(charNumber)))
elif (expression[i]=='('):
opStack.append(expression[i])
elif (expression[i]==')'):
while(opStack[-1]!='('):
valueStack.append(self.applyOperation(opStack.pop(),valueStack.pop(),valueStack.pop()))
opStack.pop()
elif(expression[i]=='+'or expression[i]=='-'or expression[i]=='*'or expression[i]=='/'):
while( (len(opStack)!=0) and ( self.opPrecedence(expression[i],opStack[-1]) ) ):
valueStack.append(self.applyOperation(opStack.pop(),valueStack.pop(),valueStack.pop()))
opStack.append(expression[i])
i = i + 1
while(len(opStack)!=0):
valueStack.append(self.applyOperation(opStack.pop(),valueStack.pop(),valueStack.pop()))
return valueStack.pop()
def applyOperation(self,op,a,b):
if op=='+':
return a+b
elif op=='-':
return a-b
elif op=='*':
return a*b
elif op=='/':
return a/b
else:
return 0
def opPrecedence(self,op1,op2):
if (op2 == '(' or op2 == ')'):
return False
if ((op1 == '*' or op1 == '/') and (op2 == '+' or op2 == '-')):
return False
else:
return True
a = evaluateString()
print(a.evalString("(5+7)"))
I am able to get the right numbers in the valueStack. However, there seems to be problem in the last two elseif. Can someone point me in the right direction?
I have done some fixes and it works for some operations. But I haven't tested it for all cases. Also, operations are only integers, no floats (e.g. check last output below).
class evaluateString:
def evalString(self,expression):
valueStack = []
opStack = []
i=0
while(i<len(expression)):
if(expression[i] == ' '):
continue
if(expression[i]>='0' and expression[i] <= '9'):
charNumber = [] #for storing number
j = i
while(j<len(expression) and expression[j]>='0' and expression[j] <= '9'):
charNumber.append(expression[j])
j += 1
i = (j-1)
valueStack.append(int(''.join(charNumber)))
elif (expression[i]=='('):
opStack.append(expression[i])
elif (expression[i]==')'):
while(opStack[-1]!='('):
valueStack.append(self.applyOperation(opStack.pop(),valueStack.pop(),valueStack.pop()))
opStack.pop()
elif(expression[i]=='+'or expression[i]=='-'or expression[i]=='*'or expression[i]=='/'):
while( (len(opStack)!=0) and ( self.opPrecedence(expression[i],opStack[-1]) ) ):
valueStack.append(self.applyOperation(opStack.pop(),valueStack.pop(),valueStack.pop()))
opStack.append(expression[i])
i = i + 1
while(len(opStack)!=0):
valueStack.append(self.applyOperation(opStack.pop(),valueStack.pop(),valueStack.pop()))
return valueStack.pop()
def applyOperation(self,op,a,b):
if op=='+':
return a+b
elif op=='-':
return b-a
elif op=='*':
return a*b
elif op=='/':
return b/a
else:
return 0
def opPrecedence(self,op1,op2):
if (op2 == '(' or op2 == ')'):
return False
if ((op1 == '*' or op1 == '/') and (op2 == '+' or op2 == '-')):
return False
else:
return True
a = evaluateString()
print(a.evalString("8*12")) #prints 96
print(a.evalString("(122-434)")) #prints -312
print(a.evalString("(232+12)/2")) #print 122
print(a.evalString("232/12+2")) #prints 21
In python eval() will evaluate infix expressions
print(eval("(5+7)/2"))
it will print the evaluated infix expression value as 6.
I'm having a lot of trouble converting infix notation to postfix.
For instance, I want to convert this
test(a(b+c), d()) - 3
into this
b c + a , d test 3 -
I tried this solution,
def composition(s):
i = 0
rpnstack = []
stack = []
ret = []
count = 0
while i < len(s) :
if i + 1 < len(s) and s[i + 1] == "(":
stack.append([count, rpnstack, s[i]])
i += 2
count = 1
rpnstack = []
elif s[i] == "(":
count += 1
rpnstack.append(s[i])
i += 1
elif s[i] == ")":
count -= 1
if count == 0:
for a in rpn(rpnstack):
ret.append(a)
a = stack.pop()
count = a[0]
rpnstack = a[1]
ret.append(a[2])
else:
rpnstack.append(s[i])
i += 1
else:
rpnstack.append(s[i])
i += 1
for a in rpn(rpnstack):
ret.append(a)
return ret
where RPN is the standard algorithm for the reverse polish notation and is is the infix string splitted with this regex
(\+|\-|\*|\/|\>|\<|\(|\)|\,)
But it only works sometimes.
This is the full implementation of the rpn function
operator = -10
operand = -20
leftparentheses = -30
rightparentheses = -40
empty = -50
operands = ["+", "-", "*", "/", ">", "<", "=", ","]
def precedence(s):
if s is '(':
return 0
elif s is '+' or '-':
return 1
elif s is '*' or '/' or '%':
return 2
else:
return 99
def typeof(s):
if s is '(':
return leftparentheses
elif s is ')':
return rightparentheses
elif s in operands:
return operator
elif s is ' ':
return empty
else :
return operand
def rpn(infix):
postfix = []
temp = []
for i in infix :
type = typeof(i)
if type is leftparentheses :
temp.append(i)
elif type is rightparentheses :
next = temp.pop()
while next is not '(' or skip > 0:
postfix.append(next)
next = temp.pop()
elif type is operand:
postfix.append(i)
elif type is operator:
p = precedence(i)
while len(temp) is not 0 and p <= precedence(temp[-1]) :
postfix.append(temp.pop())
temp.append(i)
elif type is empty:
continue
while len(temp) > 0 :
postfix.append(temp.pop())
return postfix
if i try to use the code against this infix expression:
i < test.func()
i get:
[' test.func', 'i ', '<']
and against this
i < 10
i get:
['i ', ' 10', '<']
How can I fix this?
Is there any easy way (or possible) to transform the output of fnmatch.translate into a regex that matches zero or more directories?
>>> import fnmatch
>>> fnmatch.translate("**/*.py")
'.*.*\\/.*\\.py\\Z(?ms)'
What I want is the regex fragment to put at ___ in
dirs = ['a.py', 'b/a.py', 'b/c/a.py', 'b/c/d/a.py']
r = fnmatch.translate("**/*.py").replace(".*.*", "___")
so that
[d for d in dirs if re.match(r, d)] == dirs
This attempt doesn't match in the the first two:
fnmatch.translate("**/*.py").replace('.*.*', "(.*/.*)*")
this doesn't match the first:
fnmatch.translate("**/*.py").replace('.*.*', "(.*/?)*")
and this makes the interpreter hang:
fnmatch.translate("**/*.py").replace('.*.*', "(.*|(.*/.*))*")
I'll be happy with an answer explaining why it isn't possible too..
Update: just replacing **/ with the empty string doesn't work:
dirs = ['a.py', 'b/a.py', 'b/c/a.py', 'b/c/d/a.py']
def translate(pat, repl=None):
r = fnmatch.translate(pat)
if repl:
r = r.replace(".*.*", repl)
r = re.compile(r)
return [d for d in dirs if r.match(d)]
>>> print translate("**/*.py".replace("**/", ""))
['a.py', 'b/a.py', 'b/c/a.py', 'b/c/d/a.py'] # correct
>>> print translate("b/**/*.py".replace("**/", ""))
['b/a.py', 'b/c/a.py', 'b/c/d/a.py'] # correct
>>> print translate("b/**/b.py".replace("**/", ""))
['b/a.py'] # incorrect
Actually -- you don't need to change .*.* at all, except to a single .*; rather, you need to change a single, unpaired .* to be [^/]*.
Thus, the actual translation table needed is -- not using fnmatch.translate() at all, but rolling it yourself:
`?` -> `.`
`.` -> `[.]`
`**/` -> `(?:.*/)?`
`*` -> `[^/]*`
Correctly handling [!foo] and its ilk is best done copying the logic from the upstream translate code.
Applying these rules transforms **/*.py to (?:.*/)?[^/]*[.]py, which matches all four of the names in your question:
>>> import re
>>> dirs = ['a.py', 'b/a.py', 'b/c/a.py', 'b/c/d/a.py']
>>> py_re = re.compile('(?:.*/)?[^/]*[.]py')
>>> [ 'Matches' if py_re.match(x) else 'Non-Matching' for x in dirs ]
['Matches', 'Matches', 'Matches', 'Matches']
An implementation of the transform:
def build_re(glob_str):
opts = re.compile('([.]|[*][*]/|[*]|[?])|(.)')
out = ''
for (pattern_match, literal_text) in opts.findall(glob_str):
if pattern_match == '.':
out += '[.]'
elif pattern_match == '**/':
out += '(?:.*/)?'
elif pattern_match == '*':
out += '[^/]*'
elif pattern_match == '?':
out += '.'
elif literal_text:
out += literal_text
return out
Here is a non-regex implementation of Charles' translation algorithm.
update1: this version handles leading ! as negation of the entire pattern, similarly to node.js' minimatch (https://github.com/isaacs/minimatch#comparisons-to-other-fnmatchglob-implementations).
def charles(pat):
r = ""
negate = int(pat.startswith('!'))
i = negate
while i < len(pat):
if pat[i:].startswith('**/'):
r += "(?:.*/)?"
i += 3
elif pat[i] == "*":
r += "[^/]*"
i += 1
elif pat[i] == ".":
r += "[.]"
i += 1
elif pat[i] == "?":
r += "."
i += 1
else:
r += pat[i]
i += 1
def match(d):
m = re.match(r, d)
return not m if negate else m
return [d for d in dirs if match(d)]
print charles("**/*.py")
print charles("b/**/*.py")
print charles("b/**/a.py")
print charles("!b/**/a.py")
which prints
# (?:.*/)?[^/]*[.]py
['a.py', 'b/a.py', 'b/c/a.py', 'b/c/d/a.py']
# b/(?:.*/)?[^/]*[.]py
['b/a.py', 'b/c/a.py', 'b/c/d/a.py']
# b/(?:.*/)?a[.]py
['b/a.py', 'b/c/a.py', 'b/c/d/a.py']
# b/(?:.*/)?a[.]py
['a.py']
update2: handling negations the way fnmatch does is a little more convoluted (basically fnmatch treats [!...] similarly to the regex [^...]):
def translate(pat):
r = ""
i = 0
L = len(pat)
while i < L:
if pat[i:].startswith('**/'):
r += "(?:.*/)?"
i += 3
elif pat[i] == "*":
r += "[^/]*"
i += 1
elif pat[i] == ".":
r += "[.]"
i += 1
elif pat[i] == "?":
r += "."
i += 1
elif pat[i] == '[':
i += 1
j = i
if j < L and pat[j] == '!':
j += 1
if j < L and pat[j] == ']': # make sure [!] => \[\!\]
j += 1
while j < L and pat[j] != ']':
j += 1
if j >= L:
r += '\\[' # didn't find a closing ']', backtracking
else:
stuff = pat[i:j].replace('\\', '\\\\')
i = j+1
if stuff[0] == '!':
stuff = '^' + stuff[1:] # translate negation
elif stuff[0] == '^':
stuff = '\\' + stuff # quote ^ character
r = '%s[%s]' % (r, stuff)
else:
r += re.escape(pat[i])
#r += pat[i]
i += 1
r += '\\Z(?ms)'
return r
(the negation code is stolen almost verbatim from fnmatch..)
The question I'm having problem on is calculating the postfix form expressions: for example, (1, 2, '+', 3, '*').
By calculating the expression using the following algorithm:
1. If the expression only contains an integer, return that integer.
2. Otherwise, maintain a stack. Loop through the tuple and push every element to the stack. If the element is an operator, pop the first two element out of the stack, calculate the result and push the result into the stack.
To illustrate, we take the example above. Initially, the stack is empty.
The test case is
calculate((1, 2, '*', 3, '-', 2, '*', 5, '+'))
3
whereas my first code was no good (hardcoded and all >< ):
def calculate(inputs):
if len(inputs) ==1:
return inputs[0]
elif len(inputs) == 5:
s= []
push_stack(s, inputs[0])
push_stack(s, inputs[1])
if inputs[2] == '*':
A = s.pop() * s.pop()
elif inputs[2] == '+':
A = s.pop() + s.pop()
elif inputs[2] == '-':
A= s.pop() - s.pop()
elif inputs[2] == '/':
A = s.pop() / s.pop()
s.clear()
s= [A]
push_stack(s, inputs[3])
if inputs[4] == '*':
A = s.pop() * s.pop()
elif inputs[4] == '+':
A = s.pop() + s.pop()
elif inputs[4] == '-':
A= s.pop() - s.pop()
elif inputs[4] == '/':
A = s.pop() / s.pop()
return A
else:
s= []
push_stack(s, inputs[0])
push_stack(s, inputs[1])
if inputs[2] == '*':
A = s.pop() * s.pop()
elif inputs[2] == '+':
A = s.pop() + s.pop()
elif inputs[2] == '-':
A= s.pop() - s.pop()
elif inputs[2] == '/':
A = s.pop() / s.pop()
s.clear()
s= [A]
push_stack(s, inputs[3])
if inputs[4] == '*':
A = s.pop() * s.pop()
elif inputs[4] == '+':
A = s.pop() + s.pop()
elif inputs[4] == '-':
A= s.pop() - s.pop()
elif inputs[4] == '/':
A = s.pop() / s.pop()
s.clear()
s= [A]
push_stack(s, inputs[5])
if inputs[6] == '*':
A = s.pop() * s.pop()
elif inputs[6] == '+':
A = s.pop() + s.pop()
elif inputs[6] == '-':
A= s.pop() - s.pop()
elif inputs[6] == '/':
A = s.pop() / s.pop()
s.clear()
s= [A]
push_stack(s, inputs[7])
if inputs[8] == '*':
A = s.pop() * s.pop()
elif inputs[8] == '+':
A = s.pop() + s.pop()
elif inputs[8] == '-':
A= s.pop() - s.pop()
elif inputs[8] == '/':
A = s.pop() / s.pop()
return A
Sorry for making you read that! Then I changed the style to
def calculate(inputs):
if len(inputs) ==1:
return inputs[0]
else:
s =[]
for i in inputs:
if type(i) == int:
return push_stack(s, i)
elif i is '*' or '/' or 'x' or '+':
A = s.pop()
B =s.pop()
know = operator(i, A, B)
C = push_stack(s, know)
return C
def operator(sign, one, two):
if sign == '*':
A = one * two
elif sign == '+':
A = one + two
elif sign == '-':
A= one - two
elif sign == '/':
A = one / two
return A
Am I getting closer to the idea and how does my code improve?
** Edit **
Using IDLE:
>>> calculate((1, 2, '*', 3, '-'))
[1]
>>> calculate((1, 2, '+', 3, '*'))
[1]
>>> calculate((1, 2, '*', 3, '-', 2, '*', 5, '+'))
[1]
which is not the answer I'm looking for. It should be 1 then 9 then 3.
There is a problem with
elif i is '*' or '/' or 'x' or '+':
which is treated as
elif (i is '*') or ('/') or ('x') or ('+'):
which is not what you want (it's always true). You can instead use something like:
elif i in ('*', '/', 'x', '+'):
Also:
if type(i) == int:
return push_stack(s, i)
You shouldn't be returning there. You simply want:
if type(i) == int:
push_stack(s, i)
Lastly, I think a better approach would be to always use the stack, and just return the top of the stack at the end of your function. This saves you from having to create a special case for 1-element arguments to calculate(). Putting this all together, something along the lines of this should work:
def calculate(inputs):
stack = []
for a in inputs:
if type(a) is int:
stack.append(a)
continue
op1, op2 = stack.pop(), stack.pop()
if a == '+':
stack.append(op2 + op1)
elif a == '-':
stack.append(op2 - op1)
elif a == '*':
stack.append(op2 * op1)
elif a == '/':
stack.append(op2 / op1)
return stack.pop()
Right now this does no error-checking (e.g. for malformed expressions), but it's easy to add.
Part of the problem, which you seem to have realized, is that you are trying to make one function do everything. If you take a look at what the code is doing, and try to separate out the responsibilities, you end up with something like the following:
There are some crucial differences between Python 2.x and 3.x. Where these differences would cause problems, it's easiest to introduce helper functions and define them appropriately for each version:
import sys
if sys.hexversion < 0x3000000:
# Python 2.x
is_str = lambda s: isinstance(s, basestring)
inp = raw_input
else:
# Python 3.x
is_str = lambda s: isinstance(s, str)
inp = input
You do a fair bit of stack maintenance; this can be avoided by making a Stack class which knows how to pop and push multiple items. (It should also help your out-of-order arguments problem; 4 2 - should be 4 - 2, not 2 - 4)
class Stack(list):
def pop_n(self, n):
"""
Pop n items off stack, return as list
"""
assert n >= 0, "Bad value {}: n cannot be negative".format(n)
if n == 0:
return []
elif n <= len(self):
res = self[-n:]
del self[-n:]
return res
else:
raise ValueError("cannot pop {} items, only {} in stack".format(n, len(self)))
def push_n(self, n, items):
"""
Push n items onto stack
"""
assert n == len(items), "Expected {} items, received {}".format(n, len(items))
self.extend(items)
Rather than having a single "do-any-operation" function, we can let each operator have its own self-contained code. This makes it much easier to change or add operators without funny side-effects. First we make an Operator class
class Op:
def __init__(self, num_in, num_out, fn):
"""
A postfix operator
num_in: int
num_out: int
fn: accept num_in positional arguments,
perform operation,
return list containing num_out values
"""
assert num_in >= 0, "Operator cannot have negative number of arguments"
self.num_in = num_in
assert num_out >= 0, "Operator cannot return negative number of results"
self.num_out = num_out
self.fn = fn
def __call__(self, stack):
"""
Run operator against stack (in-place)
"""
args = stack.pop_n(self.num_in) # pop num_in arguments
res = self.fn(*args) # pass to function, get results
stack.push_n(self.num_out, res) # push num_out values back
then we define the actual operators as
ops = {
'*': Op(2, 1, lambda a,b: [a*b]), # multiplication
'/': Op(2, 1, lambda a,b: [a//b]), # integer division
'+': Op(2, 1, lambda a,b: [a+b]), # addition
'-': Op(2, 1, lambda a,b: [a-b]), # subtraction
'/%': Op(2, 2, lambda a,b: [a//b, a%b]) # divmod (example of 2-output op)
}
Now that the support structure is in place, your evaluation function is simply
def postfix_eval(tokens):
"""
Evaluate a series of tokens as a postfix expression;
return the resulting stack
"""
if is_str(tokens):
# if tokens is a string, treat it as a space-separated list of tokens
tokens = tokens.split()
stack = Stack()
for token in tokens:
try:
# Convert to int and push on stack
stack.append(int(token))
except ValueError:
try:
# Not an int - must be an operator
# Get the appropriate operator and run it against the stack
op = ops[token]
op(stack) # runs Op.__call__(op, stack)
except KeyError:
# Not a valid operator either
raise ValueError("unknown operator {}".format(token))
return stack
and to make it easier to test, we can make it interactive:
def main():
while True:
expr = inp('\nEnter a postfix expression (or nothing to quit): ').strip()
if expr:
try:
print(" => {}".format(postfix_eval(expr)))
except ValueError as error:
print("Your expression caused an error: {}".format(error))
else:
break
if __name__=="__main__":
main()
This runs like
Enter a postfix expression (or nothing to quit): 1 2 * 3 -
=> [-1]
Enter a postfix expression (or nothing to quit): 1 2 + 3 *
=> [9]
Enter a postfix expression (or nothing to quit): 1 2 * 3 - 2 * 5 +
=> [3]
Enter a postfix expression (or nothing to quit): 5 2 /%
=> [2, 1]
If you are doing calculator, or something like that, you should use function eval().
It will return result of expression.