用字符串调用Python中的函数

38 投票
3 回答
73405 浏览
提问于 2025-04-16 06:46

几天前,我在网上搜索时发现了一篇关于Python字典的有趣文章。文章讲的是如何用字典里的键来调用函数。在那篇文章中,作者定义了一些函数,然后创建了一个字典,字典的键正好和函数的名字一样。这样,他就可以从用户那里获取输入参数,然后调用相应的函数(有点像实现switch-case的效果)。

之后我意识到我也想做类似的事情,但又有些不同。我想知道如何实现这个功能。

假设我有一个函数:

def fullName( name = "noName", family = "noFamily" ):
    return name += family

现在如果我有一个这样的字符串:

myString = "fullName( name = 'Joe', family = 'Brand' )"

有没有办法执行这个查询并得到结果:JoeBrand?
我记得我们可以把字符串传给exec()语句,它会为我们执行。但我不确定在这个特殊情况下该怎么做,也不知道在Python中高效的方法是什么。此外,我也很想知道如何处理函数的返回值,比如在我的例子中,如何打印出那个函数返回的全名?

3 个回答

13

我知道这个问题已经有点老了,但你可以这样做:

argsdict = {'name': 'Joe', 'family': 'Brand'}
globals()['fullName'](**argsdict)

argsdict 是一个存放参数的字典,globals 用字符串来调用函数,而 ** 则是把字典里的内容展开成参数列表。这种方法比 eval 要干净很多。唯一的问题在于如何分割字符串。这里有一个(非常复杂的)解决方案:

example = 'fullName(name=\'Joe\',family=\'Brand\')'
# Split at left parenthesis
funcname, argsstr = example.split('(')
# Split the parameters
argsindex = argsstr.split(',')
# Create an empty dictionary
argsdict = dict()
# Remove the closing parenthesis
# Could probably be done better with re...
argsindex[-1] = argsindex[-1].replace(')', '')
for item in argsindex:
    # Separate the parameter name and value
    argname, argvalue = item.split('=')
    # Add it to the dictionary
    argsdict.update({argname: argvalue})
# Call our function
globals()[funcname](**argsdict)
52

这虽然不完全回答你的问题,但也许能帮到你:

正如提到的,尽量避免使用 eval。我觉得更好的方法是使用字典解包。这种方法也很灵活,而且出错的可能性更小。

举个例子:

def fullName(name = "noName", family = "noFamily"):
    return name + family

functionList = {'fullName': fullName}

function = 'fullName'
parameters = {'name': 'Foo', 'family': 'Bar'}

print functionList[function](**parameters)
# prints FooBar

parameters = {'name': 'Foo'}
print functionList[function](**parameters)
# prints FoonoFamily
41

你可以使用 eval() 这个函数:

myString = "fullName( name = 'Joe', family = 'Brand' )"
result = eval(myString)

不过要小心,很多人认为 eval() 是个 坏东西

撰写回答