以更紧凑的方式重写python switch

Rewriting Python switch into a more compact way

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
Replacements for switch statement in python?

假设我在python中有一个列表:

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

我想根据输入运行一个函数,该输入可以是列表中的任何值。

不是为list中的每个元素编写switch case语句,而是有一种更紧凑的方式来编写它吗?

我的理由是,清单在未来会不断增加。


在Python中没有switch/case语句。

对于小的list,您要使用if/elif

1
2
3
4
5
6
7
8
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))

对于更大的list,您需要确保每种情况都是一个函数(我已经假设过,但是如果您有类似return args[0] + args[1]的代码,则必须将其更改为do_add函数),并创建一个dict映射名称到函数:

1
2
3
4
5
6
7
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))

这是因为在Python中,函数是普通的对象,可以像其他任何对象一样传递。因此,您可以将它们存储在一个dict中,从dict中检索它们,然后仍然调用它们。

顺便说一下,这一切都在常见问题解答中解释过,还有一点额外的狂热。

如果您有一些要调用的默认函数,而不是引发错误,那么很明显,如何使用if/elif/else链执行此操作,但是如何使用dict映射执行此操作?您可以通过将默认函数放入except块来实现,但有一种更简单的方法:只需使用dict.get方法:

1
2
def do_stuff(x, *args):
    return func_map.get(x, do_default)(*args)


您还可以使用这样的模式(在匆忙中,因此无法清理ATM):

1
2
3
4
5
6
7
8
9
10
11
12
>>> 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