Python动态函数名称

11

我正在寻找一种更好的方法,在Python中基于变量调用函数,而不是像下面这样使用if/else语句。每个状态码都有对应的函数。

if status == 'CONNECT':
    return connect(*args, **kwargs)
elif status == 'RAWFEED':
    return rawfeed(*args, **kwargs)
elif status == 'RAWCONFIG':
    return rawconfig(*args, **kwargs)
elif status == 'TESTFEED':
    return testfeed(*args, **kwargs)
...

我认为需要某种工厂函数,但不确定语法

8个回答

38

我猜你可能会发现getattr有用。

import module
getattr(module, status.lower())(*args, **kwargs)

谢谢您提供这个例子,我之前不知道getattr()也可以用于模块。 - drjeep

20

解决这个问题的标准方法是使用字典来模拟switchif/elif。在这里,你会找到一些类似问题的解决方案。

将你的函数放入一个字典中,以状态码作为键:

funcs = {
    'CONNECT': connect,
    'RAWFEED': rawfeed,
    'RAWCONFIG' : rawconfig,
    'TESTFEED': testfeed
}
funcs[status](*args, **kwargs)

funcs['status'] 会引发 KeyError。 - SilentGhost
我认为这是一种安全的方式,当status是意外的方法名称时,它会引发异常。 - Andrew T
DRY 很少适用于这种情况。最初的函数列表可能具有类似字符串的名称;但这通常会分化成更复杂的关系。 - S.Lott
6
这不是Python函数调度的标准方式。在这种情况下,getattr是标准方法。 - hasen
当状态变量不是外部的,例如从Web表单或其他地方获取时,或者如果函数可能被重命名为小写版本之外的其他名称时,我会使用此方法。您也可以认为这更加明确(因此更符合Python风格)。 但是,当函数列表很大或大小发生变化时,我更倾向于使用“getattr”方法。 - Brendan
显示剩余2条评论

15

假设这些函数属于某个模块:

import module
return getattr(module, status.lower()).__call__(*args, **kwargs)

6

看起来您可以以稍微不同的方式(在我看来更为优雅)使用getattr。

import math
getattr(math, 'sin')(1)

或者,如果函数像下面一样被导入
from math import sin

sin现在在命名空间中,因此您可以通过以下方式调用它

vars()['sin'](1)

4

对SilentGhost的回答进行了一些改进:

globals()[status.lower()](*args, **kwargs)

如果你想调用当前模块中定义的函数。

虽然看起来不太美观,但我会使用带有字典的解决方案。


3

链接已失效,分数减少。非常抱歉。 - Drachenfels

1
我之前也遇到过同样的问题。看看这个问题,我认为这就是你要找的答案。 字典或if语句 希望这有所帮助。
Eef

0

这是与之前版本的一些更改:

funcs = {
'CONNECT': connect,
'RAWFEED': rawfeed,
'RAWCONFIG' : rawconfig,
'TESTFEED': testfeed
}

func = funcs.get('status')
if func:
    func(*args, **kwargs)

不,它并不是。这是和heikogerlach在一开始遇到的同样错误。 - SilentGhost
1
我用变量替换了“status”,所以从技术上讲它并没有改变。我更关心的是方法而不是语义。 - drjeep

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接