3

Say I have a list with mathematical operators in it, like this

operators = ['+','-','*','/']

And I am taking a random operator from here, like this

op = random.choice(operators)

If I take two numbers, say 4 and 2, how can I get Python to do the mathematical operation (under the name 'op') with the numbers?

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
DW_0505
  • 99
  • 1
  • 7

2 Answers2

7

You better do not specify the operators as text. Simply use lambda expressions, or the operator module:

import operator
import random

operators = [operator.add,operator.sub,operator.mul,operator.floordiv]
op = random.choice(operators)

You can then call the op by calling it with two arguments, like:

result = op(2,3)

For example:

>>> import operator
>>> import random
>>> 
>>> operators = [operator.add,operator.sub,operator.mul,operator.floordiv]
>>> op = random.choice(operators)
>>> op
<built-in function sub>
>>> op(4,2)
2

So as you can see, the random picked the sub operator, so it subtracted 2 from 4.

In case you want to define an function that is not supported by operator, etc. you can use a lambda-expression, like:

operators = [operator.add,lambda x,y:x+2*y]

So here you specified a function that takes the parameters x and y and calculates x+2*y (of course you can define an arbitrary expression yourself).

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
4

You can use eval if you are absolutely certain that what you are passing to it is safe like so:

num1 = 4
num2 = 2
operators = ['+','-','*','/']
op = random.choice(operators)
res = eval(str(num1) + op + str(num2))

Just keep in mind that eval executes code without running any checks on it so take care. Refer to this for more details on the topic when using ast to do a safe evaluation.

Community
  • 1
  • 1
The Quantum Physicist
  • 24,987
  • 19
  • 103
  • 189
  • 1
    `eval(..)` is considered dangerous. You better avoid it, unless you have absolutely no choice. – Willem Van Onsem Mar 16 '17 at 14:24
  • @WillemVanOnsem Agreed. I'm just providing an answer with the given parameters :) – The Quantum Physicist Mar 16 '17 at 14:26
  • @TheQuantumPhysicist You can use the much safer `literal_eval` from the `ast` module instead – Ma0 Mar 16 '17 at 14:26
  • @TheQuantumPhysicist: perhaps it is better to provide a note about the possible risks it implies. – Willem Van Onsem Mar 16 '17 at 14:27
  • 1
    @Ev.Kounis `literal_eval` won't work with all operators, try `ast.literal_eval('2*3')`; I'm actually surprised it works with `+` and `-` – Chris_Rands Mar 16 '17 at 14:27
  • @Chris_Rands Scratch that, it was getting the `+` all the time. That is really weird though.. I am surprised the other way around.. – Ma0 Mar 16 '17 at 14:35
  • @TheQuantumPhysicist Sorry about that. I rolled it back. – Ma0 Mar 16 '17 at 14:35
  • @TheQuantumPhysicist You can also add this link to the answer: http://stackoverflow.com/questions/20748202/valueerror-malformed-string-when-using-ast-literal-eval – Ma0 Mar 16 '17 at 14:40
  • @Ev.Kounis I'm actually unclear on the rules for this, why does `ast.literal_eval` work for `+`,`-` but not other operators like `*`, `/` or `**`? I always thought it wouldn't work for any operators. The docs don't help me https://docs.python.org/3.6/library/ast.html#ast.literal_eval – Chris_Rands Mar 16 '17 at 14:41
  • 1
    @Chris_Rands It seems that in some cases, additions and subtractions also fail. See the link above, – Ma0 Mar 16 '17 at 14:42
  • 1
    @Ev.Kounis Thanks, also see: http://stackoverflow.com/questions/40584417/why-does-ast-literal-eval5-7 – Chris_Rands Mar 16 '17 at 14:46