1

How can I improve (reduce the writing) for this if-else block to run a method based on an option entered? I've tried looking at SO and various other areas for solutions but didn't find something fit my problem.

def funcA(arg1, arg2):
    ...

def funcB(arg1):
    ...

def funcC():
    ...

def funcD():
    ...

def funcE():
    ...

if option == 1:
   funcA(arg1, arg2)
elif option == 2:
   funcB(arg1)
elif option == 3:
   funcC()
elif option == 4:
   funcD()
elif option == 5:
   funcE()
else:
   pass

Apologies if the code is not clear.

8
  • 1
    It seems fine as it is, IMHO. Commented Dec 1, 2020 at 20:13
  • 1
    But it seems that you already know the answer, you mention dictionary in the title Commented Dec 1, 2020 at 20:14
  • It's not just which function to call, but what arguments to pass to that function, that depends on the value of option. You can't just write some_dict[option](...). Commented Dec 1, 2020 at 20:14
  • having differing amounts of parameters provided to functions will make it more complicated if you wrap the functions into dictonary values with options as keys. It can be done .. but you'll probably need args and kwargs and more if/elses. Just keep it as is. But change the names of functions/parameters to something more meaningful. Commented Dec 1, 2020 at 20:15
  • "I've tried looking at SO and various other areas for solutions but didn't find something fit my problem." Show us the specific things you found, and explain why they do not fit. Commented Dec 1, 2020 at 20:23

5 Answers 5

2

You could use a dictionary as a dispatch-table, and namedtuples to store a function & argument pairing.

from collections import namedtuple

def funcA(arg1, arg2):
    print(f'I am funcA and you gave me {arg1} and {arg2}')
def funcB(arg):
    print(f'I am funcB and you gave me {arg}')
def funcC():
    print(f'I am funcC')
def funcD():
    print(f'I am funcD')
def funcE():
    print(f'I am funcE')

OptionPairing = namedtuple('OptionPairing', ['f', 'args'])

dispatch = {
  1: OptionPairing(funcA, [True, False]),
  2: OptionPairing(funcB, [True]),
  3: OptionPairing(funcC, []),
  4: OptionPairing(funcD, []),
  5: OptionPairing(funcE, [])
}

for i in range(1, 6):
    choice = dispatch[i]
    x = choice.f(*choice.args)

Running this, then, gives the following results:

I am funcA and you gave me True and False
I am funcB and you gave me True
I am funcC
I am funcC
I am funcE

If you want to specify yourself what arguments to pass to your function, simply this will suffice:

dispatch = {
  1: funcA,
  2: funcB,
  3: funcC,
  4: funcD,
  5: funcE,
}

Then call your function like so:

dispatch[option](args)

Making sure to pass the arguments args, as a list, since the number of arguments is variadic.

Sign up to request clarification or add additional context in comments.

2 Comments

But the value of args almost certainly depends on the value of option as well.
Added this possibility to my answer.
1

You could have a dictionary approach?

funcs = {
    1: funcA,
    2: funcB,
    ...
}

func = funcs.get(option)
if func is None:
    return 

print(f"Running func: {func.__name__}")
func(*args, **kwargs)

Comments

0

It is common in python to do a switch-like struct with a dictionary as you said. However in your case the if/else looks ok I think since the following is a bit obfuscated:

option = 2

def funcA(arg1, arg2):
    print("A")

def funcB(arg1):
    print("B")

def funcC():
    print("C")

def funcD():
    print("D")

def funcE():
    print("E")

func, args = {
    1: (funcA, ("arg1", "arg2")),
    2: (funcB, ("arg1",)),
    3: (funcC, ()),
    4: (funcD, ()),
    5: (funcE, ()),
}.get(option, (None, (),))

if func:
    func(*args)

It really depends on how many functions and args you have but I would suggest for a few functions to stick to if/else

Comments

0

You can use a dictionary of the functions and their args :

actions = {
  1: [ func1 , [arg1,arg2] ]
  2: [ func2 , [arg1] ]
  3: [ func3 , []]
  4: [ func4 , []]
  5: [ func5 , []]
}

def doAction( actions , option ):
    if option in actions:
        func, args = actions[option]
        func(*args)

Comments

0

You can use a helper function fo imitate a switch/case statement and avoid the ugly repetitions (and corresponding maintenance hassles):

def switch(value): yield lambda *match: value in match

example usage:

for case in switch(option):
    if   case(1): funcA(arg1, arg2)
    elif case(2): funcB(arg1)
    elif case(3): funcC()
    elif case(4): funcD()
    elif case(5): funcE()

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.