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

Python function pointer with different argument size

我的问题是一些如何与这个问题相关的,我有一个函数字典,有不同数量的参数,我如何能自动调用它们?

1
2
3
4
5
6
7
8
9
10
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)
.........

而不是像上面那样叫他们每个人想要这样的东西

1
2
for i in range(len(funcdict)):
     funcdict[i](......)

不知道如何填充参数,因为每个函数的参数数量在2到6之间变化。


如果你想以一种自动的方式调用你所有的函数,特别是一次调用所有的函数,那么你可以用某个特定的名字来调用它们就不重要了,就像你正在引用的问题一样。您可以将函数保存在一个列表中,然后依次调用每个函数。

至于处理数量可变的参数,python有一个"splat"操作符,您可能在某些方法声明中看到过:def __init__(self, *args, **kwargs)。此运算符可用于解包参数列表。(更多信息请参见此答案)

如果将参数存储在另一个列表中,则可以迭代函数列表,并使用相同的语法将参数逐个应用到相应的函数,而不必指定参数的数目:

1
2
3
4
5
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])

如何将函数链接到它们的默认参数是另一回事:您可以将它们保存在两个列表中,或者作为另一个列表或dict中的元组放在一起,或者定义一个轻量级类来保存它们…这取决于您的问题。不管怎样,听起来对你来说重要的部分是*符号。

编辑:

如果要向函数传入关键字参数,可以使用double-*表示法传递字典,并将其扩展为所需的关键字参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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])


好吧,假设您将参数放在一个元组中。您还需要修改您的表,以便了解每个函数需要多少参数,这意味着要修改数据结构(您可以使用inspect模块来确定这一点,但目前这是不必要的复杂问题:

顺便说一句,如果函数必须被调用为任何特定的顺序,那么dict就不是一个好的结构,因为它以不可预测的顺序线性化,但现在我们将忽略这一点。这里有一段代码使用*表示法将元组作为单个参数传递。我正在使用一个reporter函数来显示您有参数传输工作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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])

输出为:

1
2
3
4
5
6
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')

我希望这能给你足够的咀嚼。


作为第一种可能性,我们可以通过获取func_code属性,然后查询该代码对象的co_argcount来尝试使用该函数的代码对象。

下面是一个小示例,它按名称调用字典中存储的函数,对于一组输入参数,在本例中为2, 3, 4

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/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的变量参数语法。如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/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)