传递给函数的关键字参数数量超过了最初设置的数量

12

有没有办法在函数调用时传递比函数要求更多的kwargs参数?

示例:

def mydef(a, b):
    print a
    print b

mydict = {'a' : 'foo', 'b' : 'bar'}
mydef(**mydict)    # This works and prints 'foo' and 'bar'

mybigdict = {'a' : 'foo', 'b' : 'bar', 'c' : 'nooooo!'}
mydef(**mybigdict)   # This blows up with a unexpected argument error
有没有办法在不报错的情况下传递 mybigdict?在我的理想世界中,'c' 永远不会在 mydef 中使用,并且会被忽略掉。
谢谢,我找不到我要找的东西。
编辑:修正了一下代码。 mydef(a, b, **kwargs) 是我要找的形式,但 inspect 函数参数是我新学习的东西,绝对是我工具箱中需要的。谢谢大家!

2
你提供的代码无效,第一个调用也会失败。我认为你想要在键中删除2s。 - user395760
1
@mgilson:在某些情况下,使用关键字语法来表示位置参数是完全合法且有用的。 - Martijn Pieters
@MartijnPieters -- 我并没有说这是非法的(我说这不常见)。即使通过关键字访问位置参数,我也能看到一点。但是,我无法看到将字典解包为位置参数的用途。在我看来,函数接收到的内容是不清楚的。你会使用dict而不是tuples吗?我还没有遇到过这种情况... - mgilson
@mgilson:它简化了同时使用关键字和位置参数的代码。 - Martijn Pieters
1
@deadstump -- 在我的工作流程中,我将tuples传递给位置参数,将dicts传递给默认和关键字参数。因此,我的典型函数调用可能如下所示:myfunc(*mytuple,**mydict),其中func被定义为:def func(a,b,c=2,**kwargs):,而mytuple可能是(1, 2)。显然有些人可能会以不同的方式做(就像你一直在做的那样),MartijnPieters也证实了这一点。你是对的,对于元组,顺序很重要,顺序是你将参数传递给底层函数的位置参数的顺序。 - mgilson
显示剩余3条评论
2个回答

20

除非函数定义允许更多参数(使用**kwargs catch-all语法),否则您不能调用比其定义的参数还要多的方法。

但是,您可以对该函数进行内省并删除它不接受的任何参数:

import inspect

mybigdict = {'a2' : 'foo', 'b2' : 'bar', 'c2' : 'nooooo!'}
sig = inspect.signature(mydef)
if not any(p.kind == p.VAR_KEYWORD for p in sig.parameters.values()):
    for missing in mybigdict.keys() - sig.parameters.keys():
        del mybigdict[missing]
mydef(**mybigdict)
我正在使用inspect.signature()函数来检查可调用对象是否支持**kwarg参数(通过查找Parameter.VAR_KEYWORD条目),如果不支持,则使用mybigdict.parameters映射之间的集合差异来删除方法不支持的任何内容。

我曾考虑建议在mydef的定义中添加一些**kwargs,但我认为您会同意这是一个错误的好主意:无法确保参数的顺序... - Pierre GM
1
“inspect” 方法会修改你的 “mybigdict”,这可能会产生一些不良的副作用。 - Pierre GM
1
@PierreGM:复制很容易,不是吗?我试图以相对简洁的方式说明一种技术,而不是在这里涵盖所有可能性。 - Martijn Pieters

10
为了澄清Martijn Pieters的答案,如果你改变函数签名为:def mydef(a, b, **kwargs):,那么这是可能的。这意味着如果你不介意改变签名,它将起作用。但是如果不改变签名,就无法实现。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接