views:

239

answers:

3
+4  Q: 

Python operators

I am learning Python for the past few days and I have written this piece of code to evaluate a postfix expression.

postfix_expression = "34*34*+"

stack = []

for char in postfix_expression :
    try :
     char = int(char);
     stack.append(char);
    except ValueError:
     if char == '+' :
      stack.append(stack.pop() + stack.pop())
     elif char == '-' :
      stack.append(stack.pop() - stack.pop())
     elif char == '*' :
      stack.append(stack.pop() * stack.pop())
     elif char == '/' :
      stack.append(stack.pop() / stack.pop())

print stack.pop()

Is there a way I can avoid that huge if else block? As in, is there module that takes a mathematical operator in the string form and invokes the corresponding mathematical operator or some python idiom that makes this simple?

+11  A: 

The operator module has functions that implement the standard arithmetic operators. With that, you can set up a mapping like:

OperatorFunctions = {
    '+': operator.add,
    '-': operator.sub,
    '*': operator.mul,
    '/': operator.div,
    # etc
}

Then your main loop can look something like this:

for char in postfix_expression:
    if char in OperatorFunctions:
        stack.append(OperatorFunctions[char](stack.pop(), stack.pop()))
    else:
        stack.append(char)

You will want to take care to ensure that the operands to subtraction and division are popped off the stack in the correct order.

Greg Hewgill
That's cool, I like Python. +1
Boldewyn
A: 

Just use eval along with string generation:

postfix_expression = "34*34*+"
stack = []
for char in postfix_expression:
    if char in '+-*/':
        expression = '%d%s%d' % (stack.pop(), char, stack.pop())
        stack.append(eval(expression))
    else:
        stack.append(int(char))
print stack.pop()

EDIT: made an even nicer version without the exception handling.

DzinX
Coming from a JS background: Is eval() in Python as bad/slow as in JavaScript?
Boldewyn
I don't know about slowness. It can be dangerous (i.e. unsafe) if not very carefully used, but here it's perfectly safe as all input is checked (integers or a limited character set).
DzinX
@Boldewyn: eval is generally slower than equivalent solutions that take advantage of dynamic features of Python, since there's substantial overhead in parsing and compiling each time eval() is called. Doing a dictionary lookup and using the operator module functions (OperatorFunctions["+"](2, 2)) is about 60 times faster than using eval (eval("2+2"))
Miles
Cool, thanks for the answers! So it's kind of exactly the same as in JS... (regarding to security and speed)
Boldewyn
A: 
[untested]
from operator import add, sub, mul, div
# read the docs; this is a tiny part of the operator module

despatcher = {
    '+': add,
    '-': sub,
    # etc
    }

opfunc = despatcher[op_char]
operand2 = stack.pop()
# your - and / are bassackwards
stack[-1] = opfunc(stack[-1], operand2)
John Machin
@over-zealous editor: "despatcher" is an accepted (although allegedly less common) alternative to "dispatcher". I have rolled your edit back. Please leave it alone.
John Machin
@John: Is this one of those "British English" vs. "American English things?
PTBNL
@PTBNL: I don't know. FWIW: Google hit counts (millions, 3 sig. digits): despatch 8.25, dispatch 34.6, despatcher 8.42, dispatcher 7.98. Interesting inversion.
John Machin