PLACE
spec
solutions
Python

RPN Calculator in Python

This implementation is a stack-based one. It repeatedly calls the raw_input() built-in function to read a line from the standard input, then transforms that line into a list of tokens. The latter is done by the split() method of the module string. The resulting list is fed to the for loop so that the individual tokens become the successive values of tk. An empty input line produces an empty list, for which the for loop does nothing.

All intermediate results in the course of evaluating an expression are stored in st – a list of numbers used as a stack.

If tk is one of '+', '-', '*', or '/', then finding it in the ops dictionary is successful. The two topmost numbers are popped off st, the arithmetic function corresponding to tk is obtained from ops and applied to them. If tk is not an operator, it is expected to contain a number. Whatever the case, a numeric result z is eventually produced and pushed onto the stack.

Nominally, the program is an endless loop with all its actual content placed within a try block. Upon encountering end of input, raw_input() raises the EOFError exception, which is handled by breaking the loop and eventually terminating the program.

Other exceptions may take place due to erroneous input. For example, if tk is neither an operator nor a number, the call of float, instead of producing a number, fails by raising ValueError. Calling pop raises IndexError if st is empty, showing an insufficient number of arguments for a particular arithmetic operator. Also, the assert statement raises AssertionError when the stated condition does not hold, indicating the presence of too few operators in an expression. For all these exceptions there is one universal handler which prints an error message and (implicitly) resumes the main loop.

import string, operator
ops = {'+': operator.add, '-': operator.sub, '*': operator.mul, '/': operator.div}
while True:
  try:
    st = []
    for tk in string.split(raw_input()):
      if tk in ops:
        y,x = st.pop(),st.pop()
        z = ops[tk](x,y)
      else:
        z = float(tk)
      st.append(z)
    assert len(st)<=1
    if len(st)==1: print(st.pop())
  except EOFError:  break
  except:  print('error')

The above program is written in the so called Python 2 dialect of the language. A major revision of the language, Python 3, is partially incompatible with the said dialect. With the following changes, the RPN calculator adapts to Python 3.

The div function from the operator module is renamed to truediv. The raw_input function is renamed to input. The split function in Python 3 does not belong to the string module. Along with many other former members of string, it is now a method of a built-in string class, supplying frequently needed operations on textual data. The string module is not needed and is not imported in the Python 3 version of the calculator.

import operator
ops = {'+': operator.add, '-': operator.sub, '*': operator.mul, '/': operator.truediv}
while True:
  try:
    st = []
    for tk in input().split():
      if tk in ops:
        y,x = st.pop(),st.pop()
        z = ops[tk](x,y)
      else:
        z = float(tk)
      st.append(z)
    assert len(st)<=1
    if len(st)==1: print(st.pop())
  except EOFError:  break
  except:  print('error')

boykobbatgmaildotcom