关于python:解包关键字参数,但只包含与函数匹配的参数

Unpacking keyword arguments, but only the ones that match the function

假设我有一个函数:

1
2
def foo(a=None, b=None, c=None):
  return"a:%s, b:%s, c:%s" % (a, b, c)

我有一个字典,上面有一些(或没有)参数,但也有一些键不是函数中的命名参数,例如:

1
d = {'a': 1, 'x': 4, 'b': 2, 'y': 5}

如果调用下面的函数,我将得到一个错误,因为"x"和"y"不是foo函数中的关键字参数。

1
foo(**d)  # error

是否有一种优雅的方式将参数从字典传递到函数,但只传递那些键与函数参数匹配的值?

如果我的参数/参数术语已关闭,请更正我的错误。


1
2
def foo(a = None, b=None, c=None,**extras):
    return"a:%s, b:%s, c:%s" % (a, b, c)

这里,**extras将收集所有额外的命名/关键字参数。


@Ashwini Chaudhary有一个很好的方法来解决你的问题。但是,它需要更改您的foo函数的签名。

如果不想更改函数签名,可以使用自省来了解函数期望的参数:

1
2
3
4
5
6
7
8
9
arg_count = foo.func_code.co_argcount
args = foo.func_code.co_varnames[:arg_count]

args_dict = {}
for k, v in d.iteritems():
    if k in args:
        args_dict[k] = v

foo(**args_dict)


有趣的问题。我认为现实生活中的大多数人都使用@ashwini chaudhary的方法。

我同意@rodrigue的观点,有时您不能修改函数的调用签名(可能是其他人的模块)。

如果发生这种情况,请使用函数修饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from inspect import getargspec
from funtools import wraps

def allow_kwargs(foo):
    argspec = getargspec(foo)
    # if the original allows kwargs then do nothing
    if  argspec.keywords:
        return foo
    @wraps(foo)
    def newfoo(*args, **kwargs):
        #print"newfoo called with args=%r kwargs=%r"%(args,kwargs)
        some_args = dict((k,kwargs[k]) for k in argspec.args if k in kwargs)
        return foo(*args, **some_args)
    return newfoo


# with your function:
@allow_kwargs
def foo(a = None, b=None, c=None):
  return"a:%s, b:%s, c:%s" % (a,b,c)

# with someone_elses function:
from some_place import foo
foo = allow_kwargs(foo)

functools中的@wraps使__name____doc__字符串保持一致。你也可以:

  • 从decorators模块中查看FunctionMaker,但这应该是一种更可重用的方法。
  • 修改newfoo以允许额外的非关键字var不通过。