Python 从函数集合中获取各自的*args、**kwargs,然后用提供的1d参数填充不规则的2d结构

Python 从函数集合中获取各自的*args、**kwargs,然后用提供的1d参数填充不规则的2d结构,python,python-2.7,functional-programming,list-comprehension,inspect,Python,Python 2.7,Functional Programming,List Comprehension,Inspect,我有这样的数据: args, kwargs = (('foo', 'bar', 'baz'), {'goo': 1}) for pair in format: however_many = len(pair[0]) argues.append((args[positional_index:positional_index+however_many], {k: kwargs[k] for k in pair[1]})) positional_index += howeve

我有这样的数据:

args, kwargs = (('foo', 'bar', 'baz'), {'goo': 1})
for pair in format:
    however_many = len(pair[0])
    argues.append((args[positional_index:positional_index+however_many], {k: kwargs[k] for k in pair[1]}))
    positional_index += however_many
我有一些函数,在一个对象中,它们需要这些数据作为参数。它们将通过具有此类签名的方法提供(表示为
*args
):

或者,更明确地说,在其结构中:

callFunctions(((args ...), {kwargs ...}), ...)
(我希望我对这种方法的期望足够清楚。)

举个例子,我的两个函数如下:

def func1(foo, bar):
    print foo, bar

def func2(baz, goo=0):
    print baz, goo

funcs = func1, func2    # for iteration
在这样的背景下,我有两个问题

获取每个函数的
*args
**kwargs
格式 我一直在尝试使用
inspect
模块获取每个函数的参数规范,这样我就可以用
args
kwargs
中的1d数据“填充”结构。我尝试了以下方法:

format = [(spec.args, spec.keywords) for spec in (inspect.getargspec(func) for func in funcs)]
argues = []
positional_index = 0
format = ((('foo', 'bar'), {}), (('baz',), {'goo': 0}))
for pair in format:
    however_many = len(pair[0])
    argues.append((tuple(args[positional_index:however_many]), dict({(k, kwargs[k]) for k in pair[1]})))
    positional_index += however_many
但是我不明白为什么
spec.keywords
总是给我
None
(似乎有点愚蠢)。任何关键字参数的默认值都将出现在
spec.defaults
中,但我不知道如何将其与正确的关键字参数相关联。(同样令人沮丧的是,所有关键字参数都被放入
spec.args

填写要传递给
callFunctions
假设我有这个结构,用原始数据填充这个结构是很棘手的:基本上,我想用第一个位置参数和适当的关键字参数填充第一个元组
*args、**kwargs
;然后,移动到下一个元组,其中包含下一个位置参数和适当的关键字参数;等等我尝试了以下方法:

format = [(spec.args, spec.keywords) for spec in (inspect.getargspec(func) for func in funcs)]
argues = []
positional_index = 0
format = ((('foo', 'bar'), {}), (('baz',), {'goo': 0}))
for pair in format:
    however_many = len(pair[0])
    argues.append((tuple(args[positional_index:however_many]), dict({(k, kwargs[k]) for k in pair[1]})))
    positional_index += however_many
但我明白了:

[(('foo', 'bar'), {}), ((), {'goo': 1})]

为什么我不能得到你问题的第一部分的
baz

:问题是(在Python 2中)“关键字”和“位置”参数本身没有完全的区别。任何参数值都可以按位置传递或按关键字传递。只是如果参数没有默认值,就必须提供该参数——但它仍然可以通过关键字传递。(在Python3中,可以有不能按位置传递的纯true关键字参数。)

因此,将参数与其默认值匹配的方法是认识到默认值只能应用于最后一个参数。因此,如果一个函数接受四个参数,并且有两个默认参数值,那么这些值必须用于第三个和第四个参数,前两个参数没有默认值。用一般的说法,这是一个具有两个位置参数和两个关键字参数的函数(尽管,正如我所提到的,这只是半精确的,因为任何参数都可以通过关键字传递)。如前所述,
getargspec
结果的
keywords
部分不是用来保存关键字参数的;它包含关键字varargs参数的名称(例如,
**kwargs
),如果有

要查看如何匹配它们,只需查看
inspect.formatargspec
的源代码,它基本上就是这样做的(我稍微修改了一下,以构建一个列表而不是字符串表示):

对于问题的第二部分,问题只是从
positional\u index:however\u many
切片,而不是从
positional\u index:positional\u index+however\u many
切片。此外,你的听写/集合混淆是因为你使用的是集合理解而不是听写理解。另外,您不需要调用
tuple
。这样做:

args, kwargs = (('foo', 'bar', 'baz'), {'goo': 1})
for pair in format:
    however_many = len(pair[0])
    argues.append((args[positional_index:positional_index+however_many], {k: kwargs[k] for k in pair[1]}))
    positional_index += however_many
但是请注意,这样做的一个问题是,您无法将相同名称的不同值关键字参数传递给不同的函数。如果您有
def-foo(a,b,c=2)
def-bar(a,b,c=8)
,则无法将
{c':1}
传递到
foo
{c':2}
传递到
bar
,因为您在开始时只传递一个dict,它只能有一个
'c'


更一般地说,如果您真的想处理任何合法参数集,它就不会像这样简单,因为即使是“位置”参数也可以通过关键字传递。如果你有一个像
def foo(a,b,c=3,d=4)
这样的函数,用
foo(1,d=8,c=7,b=6)
调用它是合法的——你可以按顺序传递关键字参数,也可以按关键字传递
b
的值,即使它没有默认值。因此,一般来说,您不能仅仅根据没有默认值的参数数量获取位置参数;您必须实际查看哪些特定参数是通过关键字传递的,并且只按位置传递那些没有通过关键字传递的参数。(你当然可以说你的函数在这种情况下不起作用;这取决于你希望它有多普遍。)

我不明白你问题的第二部分。如果已经将它分离为
('foo','bar'),{}
('baz',),{'goo':0}
,为什么需要进行任何进一步的处理?这些对中的每一个都已经是一个函数的参数集,因此您可以对它们进行迭代并传递每一个。@BrenBarn为了清楚地说明配对,我提供了与两个函数中的参数同名的
args
kwargs
字符串,但它们可以是任何东西。例如,在我问题的一开始提供的
args,kwargs
可以是
((1,2,3),{'hello':'world'})
。啊,我现在明白了。您的错误更简单,请参阅我编辑的答案。感谢您在
dict
/
set
理解中的注释。我现在正试着去探索它的其余部分。顺便说一下,只要我可以使用
*
语法将其作为
*args
-ca传递,我就可以不将该片段强制转换为
元组