关于python:动态选择函数

Choosing the Function Dynamically

我有一些代码如下所示:

1
2
3
4
5
6
if command == 'a':
    do_a(a, b, c)
elif command == 'b':
    do_b(a, b, c)
elif command == 'c':
    do_c(a, b, c)

我怎样才能用更优雅的东西来代替这种东西呢?也许,在Do_u[command](a,b,c)中,调用的函数依赖于该命令的一些内容?

有可能吗?


您可以在dict中存储命令,并在需要时进行查找:

1
2
3
4
5
6
7
8
9
10
11
12
In [15]: commands = {'mul': lambda x,y: x*y,
                     'add': lambda x,y: x+y}

In [16]: commands['mul'](3,4)
Out[16]: 12

In [17]: commands['add'](3,4)
Out[17]: 7

In [18]: command = 'add'; vars = (4,5)
In [19]: commands[command](*vars)
Out[19]: 9

您应该检查command是否确实在commands中:

1
2
3
4
if command in commands:
    commands[command]()
else:
    # handle error

1
2
3
4
5
6
def do(fname):
    return {'a':do_a, 'b':do_b, 'c':do_c}.get(fname)

def do_a(x,y,z): return x + y + z
def do_b(x,y,z): pass
def do_c(x,y,z): pass

用途:

1
2
do('a')(1,2,3)
6


您可以使用"反射"执行类似的操作,通过字符串名称调用函数,如下所示:

python:从字符串名称调用函数

但是

如果您不能完全控制作为command传递的内容,那么它就不会更优雅,更不可读,更容易出错。

你的版本很好:

Explicit is better than implicit.

Simple is better than complex.

如果您真的想避免使用elif的方法,我将使用注释中建议的dict函数方法。

像这样的事情,离埃瓦尔远点。


这可能有助于您,这里souce可以是任何以函数名结尾的通用模块路径,如模函数

因此,示例调用看起来像convertStringToFunction(module.funcname)

1
2
3
4
5
6
7
8
9
10
11
12
def import_module(name):
    mod = __import__(name)
    components = name.split('.')
    for comp in components[1:]:
        mod = getattr(mod, comp)
return mod

def convertStringToFunction(source):
    tempArr = source.rsplit('.',1)
    mod = import_module(tempArr[0])
    func = getattr(mod, tempArr[1])
    return func

我在等待其他人提出更好的解决方案,但:

1
2
3
4
def dispatch(cmd, *args):
   globals()['do_' + cmd](*args)

def do_a(a, b, c):

用途:

1
dispatch('a', 1, 2, 3)

显然不健壮,但是dispatch可以确保函数的存在。

一个很好的方法可能是使用装饰师。

1
2
3
4
5
6
7
@command()
def do_a(a,b,c):
    ...

@command("do_x")
def myfunc(a, b, c):
   ...

您的装饰师可以维护分派查找表等。

这取决于您有多担心可能需要使用现有函数或担心名称冲突。