I'm implementing a program that needs a RPN calculator function, I've got the one bellow, but being new to python I wonder if I can optimize it without losing the readability.
Found some solutions using dictionaries and so on, but I got lost in the 'pythonesque' parts, the lists are still somewhat of a mistery to me...
my function is :
def parseRPN(expression):
"""Parses and calculates the result fo an RPN expression
takes a list in the form of ['2','2','*']
returns 4
"""
try:
stack = []
for val in expression:
if val in ['-', '+', '*', '/']:
op1 = stack.pop()
op2 = stack.pop()
if val=='-': result = op2 - op1
if val=='+': result = op2 + op1
if val=='*': result = op2 * op1
if val=='/':
if op1==0:
result=1
else:
result = op2 / op1
stack.append(result)
elif val in ['sin','cos']:
op1 =stack.pop()
if val=='sin': result = sin(op1)
if val == 'cos': result = cos(op1)
stack.append(result)
else:
stack.append(float(val))
return stack.pop()
except:
print('error parse RPN fn:parse_rpn :' + str(expression))
return 10*10**10
Thanks in advance
This is my version:
In the first five lines after the imports I make local names for the operators and constants as an optimization so we don't have to do a module lookup every time we use one. Allowing constants like
e
andpi
is an extra feature.The
ops
dictionary is key to the working of the calculator. It links the symbol of an operator to a tuple containing the number of arguments that the operator consumes and the function to call. Because of this data structure, operators do not have to be handled specially by their number of arguments.Furthermore we save the keys for the
_ops
and_consts
dicts in tuples, since we'll be using these a lot.The line
stack[-n:] = [op(*args)]
is the heart of the calculator. It contains two tricks. First it does argument unpacking using the*
operator. Second it replaces multiple values on the stack with the result ofop
.Intentionally, this function does not catch exceptions caused by errors in the input data.
The original implementation is fine, and clear. Here's another that uses more Pythonic features:
tests using py.test (<3)
parse errors are left alone, as they already indicate what's going on
the
operator
module is used directly for many two-argument functions, like multiplylikewise, single-argument math functions like
sin
/cos
just call themath
libraryfor convenience, the expression can be specified as a single string, like
"2 3 /"
Calculators are a lot of fun, and are a great introduction to cool topics like compiling and parsing. Have fun!
RPN calculator