0

Am trying this small piece of code which can be alternative for switch. But i get weired Error.

def main(x):

    x = x.split(' ')
    return {'Function1' : Function1(x),
            'Function2' : Function2(x),
            }[x[0]]


def Function1(x):
    var1 = x[0]
    var2 = x[1]

def Function2(x):
    print x[0]

main("Function1 10")

Now the above code work fine. Problem is if i pass Function2 as key without any arguments to main function it automatically goes into Function1 and throws list out of range error.

main("Function2")

Thanks in Advance.

taz
  • 47
  • 9
  • In `Function2` you did not define any variable `x` but you are accessing its 1st element – mirosval Aug 23 '16 at 09:15
  • @mirosval it does not go into fun2 itself. – taz Aug 23 '16 at 09:17
  • 1
    There are a few differences between what you can do with dictionaries as opposed to common switch statements from other languages. Perhaps frame the question in what you're trying to do and how. Mapping values to functions can be done with a mapping (sort of what you're doing), no switch statement needed. – Reut Sharabani Aug 23 '16 at 09:20

3 Answers3

3

Your code doesn't work at all. You always call the functions when you define the dict. You should keep the callable in the dict and call the result.

def main(x):
    x = x.split(' ')
    func = {'Function1' : Function1,
            'Function2' : Function2,
           }[x[0]]
    return func(x[1])
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • Whay you write is true, But this will not work for missing keys (no "default"). Also, there is no fall-through behavior (so can't be used for, say, a duff-device) which is also worth mentioning. – Reut Sharabani Aug 23 '16 at 09:18
  • @Daniel But I cannot pass multiple aruguments to my function using this code. – taz Aug 23 '16 at 09:25
  • Default behaviour is easily achieved by using get instead of indexing. eg func.get(x[0], Function3) – Tim Aug 23 '16 at 09:26
  • Why not? Just replace `x[1]` with whatever arguments you want to pass. – Daniel Roseman Aug 23 '16 at 09:27
  • @taz You could change func(x[1]) to func(*x[1:]) to allow for arbitrary numbers of arguments. – Tim Aug 23 '16 at 09:28
1

The code block

    return {'Function1' : Function1(x),
        'Function2' : Function2(x),
        }[x[0]]

is evaluated first as

    return {'Function1' : Function1(x),
        'Function2' : Function2(x),
        }

Evaluating this will actually call both Function1 and Function2.

What you want is to get a reference to the correct function without actually calling it until you know which one you want to call:

    return {'Function1' : Function1,
        'Function2' : Function2,
        }[x[0]](x)
L3viathan
  • 26,748
  • 2
  • 58
  • 81
Levi
  • 760
  • 4
  • 8
0

What you really should do is use a string of if/elif/else statements:

if x == 1:
    Function1()
elif x == 2:
    Function2()
else:
    Function3()
mirosval
  • 6,671
  • 3
  • 32
  • 46
  • 2
    _should do_ is slightly harsh, using a mapping instead of lots of ifs is valid programming technique, and storing callables in such mapping is [nothing outrageous in Python](http://stackoverflow.com/questions/9205081/python-is-there-a-way-to-store-a-function-in-a-list-or-dictionary-so-that-when). – Łukasz Rogalski Aug 23 '16 at 09:23
  • Depends on how many cases you have and wether they need to be dynamic. For a few static cases this is certainly a lot more readable. Now the OP has 2 cases that do not need to be dynamically extended and he does not mention any of these requirements, so presumably simple is better than complex. – mirosval Aug 23 '16 at 09:36