具有不同参数大小的Python函数指针

1 投票
3 回答
3805 浏览
提问于 2025-04-17 20:41

我的问题和这个问题有点关系。我有一个包含不同数量参数的函数字典,我该如何自动调用它们呢?

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 个回答

0

首先,我们可以尝试通过获取函数的 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)
1

好的,假设你把你的参数放在一个元组里。你还需要调整你的表格,以便知道每个函数需要多少个参数,这就意味着你需要修改你的数据结构(你可以使用 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')

希望这些内容能给你带来一些启发。

2

如果你想要自动调用所有的函数,也就是说一次性调用所有函数,那么你不需要像问题中提到的那样通过特定的名字来调用它们。你可以把这些函数放在一个列表里,然后一个一个地调用。

至于处理可变数量的参数,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])

撰写回答