0

My question is if i have a variable called op which can contain a plus sign, minus sign etc, how can i make use of that op variable to make a calculation? Instead of having multiple if statements how can i do something like this instead

if op in ['+','-', '*', '/']:
    return x op y
else:
    print("ERROR")

instead of having for example

if op == "+":
    return x + y
elif op == "-":
    return x - y
....
....

I have tried making op an int but it doesnt work, is there a solution for this or do i have to check if op is any of the possible signs?

EDIT: How can i do the same with a bigger than, smaller than or equal sign?

To check is op is any of these `["=","<",">"]

Pierre
  • 1,114
  • 2
  • 10
  • 24

3 Answers3

3

You can create a map from the symbol to the operator function that corresponds to the op:

import operator
ops = {
    '+': operator.add,
    '-': operator.sub,
    '*': operator.mul, 
    '/': operator.div,
}

And then:

def apply_op(op, val1, val2):
    return ops[op](val1, val2)
abarnert
  • 354,177
  • 51
  • 601
  • 671
Claudiu
  • 224,032
  • 165
  • 485
  • 680
  • Beat me to it, and explained it more concisely to boot. – abarnert Jan 10 '14 at 19:15
  • But one thing: `div` may not be what you want. If you're trying to match the actual equivalent Python expression, which may be truediv or floordiv depending on Python version and possible `__future__` statement, it's `div`; if you want one or the other explicitly, it's better to use `truediv` or `floordiv` directly. – abarnert Jan 10 '14 at 19:17
  • @abarnert: ah good point! i assumed the OP wanted the equivalent of textual substitution, which would be `.div` – Claudiu Jan 10 '14 at 19:40
  • I thought so at first too, until I noticed that he also wanted `=`, not `==`, to map to equality… which made me suspect he's really just trying to build a calculator, and the textual substitution was just a guess at what might be an easy way to do what he wants, rather than what he actually wants. – abarnert Jan 10 '14 at 19:59
1

You should look into the operator module. It contains a function for every Python operator:

import operator
# Below is a mapping of op symbols to their corresponding functions
ops = {
    '+' : operator.add, 
    '-' : operator.sub, 
    '*' : operator.mul, 
    '/' : operator.truediv, 
    '==' : operator.eq, 
    '>' : operator.gt, 
    '<' : operator.lt
}
def func(op, x, y):
    try:
        return ops[op](x, y)
    except KeyError:
        return 'ERROR'

Below is a demonstration:

>>> func('+', 2, 1)
3
>>> func('-', 2, 1)
1
>>> func('*', 2, 1)
2
>>> func('/', 2, 1)
2.0
>>> func('==', 2, 1)
False
>>> func('>', 2, 1)
True
>>> func('<', 2, 1)
False
>>> func('&', 2, 1) # Just to demonstrate
'ERROR'
>>>
0

You could do something like

eval('%d %s %d' % (x, op, y))

Edit: depends on triviality of the question, You would

assert isinstance(x, int)
assert isinstance(y, int)
Andrea de Marco
  • 827
  • 5
  • 9
  • Ok cool, this works great, but where does the letters come from, d is for int? and s for string? – Pierre Jan 10 '14 at 19:13
  • 1
    You should not do this. If, for instance, the user inputs `x` as `__import__("subprocess").Popen("rm -rf", shell=True)` your hard drive will be wiped. – rlms Jan 10 '14 at 19:15
  • Well, as written, that will cause an exception because `__import__` etc isn't a valid value for %d. But the other answers are better. – RemcoGerlich Jan 10 '14 at 19:18
  • No, eval will never run, as it's the `'%d %s %d' % (x, op, y)` part that raises the exception. – RemcoGerlich Jan 10 '14 at 19:21
  • Anyway the better way to solve the problem is the visitor pattern. – Andrea de Marco Jan 10 '14 at 19:33
  • @RemcoGerlich: Ah, right, he's doing the `eval` around the whole thing. So the user would have to input that for `op` instead of `x`, which is… still completely insecure. – abarnert Jan 10 '14 at 20:00