0

Possible Duplicate:
Replacements for switch statement in python?

Suppose I have a list in Python:

list = ('ADD', 'SUB', 'PUSH', 'POP')

I want to run a function depending on input, and that input can be any value in the list.

Instead of writing a switch case statement for each element in list, is there a more compact way of writing it?

My reasoning is for the case of the list growing in the future.

Community
  • 1
  • 1
drum
  • 5,416
  • 7
  • 57
  • 91
  • See here: http://stackoverflow.com/q/60208/562139 – scorpiodawg Feb 05 '13 at 01:49
  • 1
    By the way, you shouldn't call a variable `list`, because that's the name of the built-in `list` type. (It's even more confusing in this case, because your object isn't a `list`, it's a `tuple`.) – abarnert Feb 05 '13 at 02:24
  • Thanks for the clarification. So many terms from so many languages...waaaah! – drum Feb 05 '13 at 03:48

2 Answers2

5

Well, there is no switch/case statement in Python.

For a small list, you want to use if/elif:

def do_stuff(x, *args):
    if x == 'ADD':
        return do_add(*args)
    elif x == 'SUB':
        return do_sub(*args)
    # …
    else:
        raise RuntimeError('Never heard of {}'.format(x))

For a larger list, you want to make sure each case is a function (I already assumed that above, but if you had code like return args[0] + args[1], you'd have to change that into a do_add function), and create a dict mapping names to functions:

func_map = {'ADD': do_add, 'SUB': do_sub, … }

def do_stuff(x, *args):
    try:
        return func_map[x](*args)
    except KeyError:
        raise RuntimeError('Never heard of {}'.format(x))

This works because in Python, functions are normal objects that you can pass around like any other objects. So, you can store them in a dict, retrieve them from the dict, and still call them.

By the way, this is all explained in the FAQ, along with a bit of extra fanciness.

If you have some default function you'd like to call instead of raising an error, it's obvious how to do that with the if/elif/else chain, but how do you do it with the dict map? You could do it by putting the default function into the except block, but there's an easier way: just use the dict.get method:

def do_stuff(x, *args):
    return func_map.get(x, do_default)(*args)
abarnert
  • 354,177
  • 51
  • 601
  • 671
  • 1
    @Lattyware: You had a bit of nice extra explanation, which I'll steal to improve my answer. – abarnert Feb 05 '13 at 01:53
  • Instead of raising an Error for a key not found, would it work to default x? – drum Feb 05 '13 at 02:15
  • @drum: Sure, if that's what you want, you can do that. In that case, you may want to replace the `try`/`map[x]`/`except` with a `map.get`. I'll edit the answer. – abarnert Feb 05 '13 at 02:20
0

You could also use a pattern such as this (in a hurry so can't clean it up atm):

>>> class Test(object):
...     def test_FOO(self):
...             print 'foo'
...     
...     def test_BAR(self):
...             print 'bar'
... 
>>> def run_on(cls, name):
...     getattr(cls, 'test_%s' % name)()
... 
>>> run_on(Test(), 'FOO')
foo
Demian Brecht
  • 21,135
  • 5
  • 42
  • 46