1

I have four subroutines to multiply, divide, add and subtract 2 numbers which I will ask the user for.

My unfinished code is:

def multiply(a, b):
    print(f"{a} x {b} = {a*b}")
    
def divide(a, b):
    print(f"{a} รท {b} = {a*b}")

num1 = int(input("What is the first number?\n"))
num2 = int(input("What is the second number?\n"))
calculation = input("What calculation would you like to perform? [multiply, divide]\n")

calculation(num1, num2)

but it gives TypeError: 'str' object is not callable

Is it necessary to use if statements like:

if calculation == 'multiply':
     multiply()
elif calculation == 'divide':
     divide()

for all four subroutines or can I use the variable calculation to substitute for the function name.

Stray
  • 15
  • 5
  • 1
    Use a dict with a string mapping to a function: `{"divide": divide}` โ€“ dawg Feb 25 '22 at 18:52
  • You use variables to call functions all the time. `multiply` and `divide` are both variables bound to `function` objects. โ€“ chepner Feb 25 '22 at 19:00
  • @chepner but you're obviously aware that OP means *string* variable, right? ;) โ€“ timgeb Feb 25 '22 at 19:09

1 Answers1

0

Use a dictionary to hold your functions

funcs = {'multiply': multiply, 'divide': divide}

and then access funcs[calculation].

... or if you have a DRY fetish:

funcs = {f.__name__: f for f in [multiply, divide]}

Demo:

>>> funcs['multiply'](3, 4)
3 x 4 = 12

You could also access the globals() dict

>>> globals()['multiply'](3, 4)
3 x 4 = 12

but this is not such a good idea because the function to call comes from user input and who knows what weird callables are in globals().


Bonus: safeguarding against bad input

from functools import partial
def notfound(fname, *_, **__):
    print(f'function {fname!r} not found')

Usage:

>>> calculation = 'multiply'
>>> funcs.get(calculation, partial(notfound, calculation))(3, 4)
3 x 4 = 12
>>> calculation = 'none'
>>> funcs.get(calculation, partial(notfound, calculation))(3, 4)
function 'none' not found
timgeb
  • 76,762
  • 20
  • 123
  • 145