具有不同参数大小的Python函数指针
我的问题和这个问题有点关系。我有一个包含不同数量参数的函数字典,我该如何自动调用它们呢?
funcdict = {
'mypackage.mymodule1.myfunction1': mypackage.mymodule.myfunction,
'mypackage.mymodule2.myfunction2': mypackage.mymodul2.myfunctio2,
....
}
funcdict[0](parameter1, parameter2)
funcdict[1](parameter1, parameter2, parameter3)
funcdict[1](parameter1, parameter2, parameter3,parameter4,parameter5)
.........
我不想像上面那样一个个调用它们,而是想要类似这样的方式
for i in range(len(funcdict)):
funcdict[i](......)
我不知道该如何填充参数,因为每个函数的参数数量从2到6不等。
3 个回答
首先,我们可以尝试通过获取函数的 func_code
属性来使用代码对象,然后查询这个代码对象的 co_argcount
属性,来了解这个函数需要多少个参数。
下面是一个小例子,它通过名字从字典中调用函数,并传入一组输入参数,这里是 2, 3, 4
:
#!/usr/bin/env python
def f1(a, b):
print "executing f1 with %d, %d" % (a, b)
return a*b
def f2(a, b, c):
print "executing f2 with %d, %d, %d" % (a, b, c)
return a*b+c
def call_functions(arg1, arg2, arg3):
funcdict = {
"add" : f1,
"madd" : f2
}
for f in funcdict.itervalues():
if f.func_code.co_argcount == 2:
f(arg1, arg2)
elif f.func_code.co_argcount == 3:
f(arg1, arg2, arg3)
# and so on
if __name__=="__main__":
call_functions(2, 3, 4)
还有一种稍微简单一点的方法(你不需要为每个函数明确检查参数的数量,函数只会使用它们需要的参数)是使用Python的可变参数语法。这样写会是:
#!/usr/bin/env python
def f1(*args):
print "executing f1 with %d, %d" % (args[0], args[1])
return args[0]*args[1]
def f2(*args):
print "executing f2 with %d, %d, %d" % (args[0], args[1], args[2])
return args[0]*args[1]+args[2]
def call_functions(*args):
funcdict = {
"add" : f1,
"madd" : f2
}
for f in funcdict.itervalues():
f(*args)
if __name__=="__main__":
call_functions(2, 3, 4)
好的,假设你把你的参数放在一个元组里。你还需要调整你的表格,以便知道每个函数需要多少个参数,这就意味着你需要修改你的数据结构(你可以使用 inspect
模块来确定这一点,但现在这样做有点复杂,不太必要)。
顺便说一下,如果函数需要按照特定的顺序调用,使用字典就不太合适,因为字典的顺序是不可预测的,不过我们暂时不讨论这个。下面是一段代码,使用 * 符号将元组作为单独的参数传递。我用一个报告函数来展示参数传递是如何工作的。
parameters = ("one", "two", "three", "four", "five")
def reporter(*args):
print("Called with", len(args), "arguments")
print("args are:", args)
funcdict = {
'mypackage.mymodule1.myfunction1': (reporter, 1),
'mypackage.mymodule2.myfunction2': (reporter, 5),
}
for name, (function, arg_ct) in funcdict.items():
print("Testing", name)
function(*parameters[:arg_ct])
输出结果是:
Testing mypackage.mymodule1.myfunction1
Called with 1 arguments
args are: ('one',)
Testing mypackage.mymodule2.myfunction2
Called with 5 arguments
args are: ('one', 'two', 'three', 'four', 'five')
希望这些内容能给你带来一些启发。
如果你想要自动调用所有的函数,也就是说一次性调用所有函数,那么你不需要像问题中提到的那样通过特定的名字来调用它们。你可以把这些函数放在一个列表里,然后一个一个地调用。
至于处理可变数量的参数,Python 有一个叫做“星号”的操作符,你可能在一些方法的定义中见过:def __init__(self, *args, **kwargs)
。这个操作符可以用来解包参数列表。(想了解更多信息,可以看看这个回答)
如果你把参数存储在另一个列表中,你可以遍历你的函数列表,并使用相同的语法将参数一个一个地应用到对应的函数上,而不需要指定参数的数量:
funclist = [lambda x,y: x+y, lambda x,y,z: x+y+z, lambda x: -x]
paramlist = [(1,2), (1,2,3), (1,)]
for index, func in enumerate(funclist):
print func(*paramlist[index])
如何将函数与它们的默认参数关联起来是另一个问题:你可以把它们放在两个列表中,或者把它们作为元组放在另一个列表或字典中,或者定义一个轻量级的类来保存它们……这取决于你的具体问题。总之,听起来对你来说重要的部分是*
这个符号。
编辑:
如果你想要将关键字参数传递给函数,可以使用双星号(**)的写法来传递一个字典,并将其展开为所需的关键字参数:
def func1(n_samples, noise, factor, random_state):
print locals()
def func2(n_samples, ratio, noise):
print locals()
def func3(my_key, default_key='world!'):
print locals()
funclist = [func1, func2, func3]
paramlist = [
dict(
n_samples=1000,
noise=0.3,
factor=0.5,
random_state=1
),
dict(
n_samples=1000,
ratio=0.5,
noise=0.1
),
dict(
my_key='hello',
)
]
for index, func in enumerate(funclist):
func(**paramlist[index])