22

假设我有一个功能:

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

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

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

如果我调用以下命令,我会得到一个错误,因为 'x' 和 'y' 不是 foo 函数中的关键字参数。

foo(**d)  # error

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

如果我的参数/参数术语不正确,请纠正我。

4

3 回答 3

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

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

于 2012-06-16T17:06:39.603 回答
10

@Ashwini Chaudhary 有一种非常 Pythonic 的方式来解决您的问题。但是,它需要更改foo函数的签名。

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

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)
于 2012-06-16T17:17:33.420 回答
8

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

我同意@Rodrigue 的观点,有时您无法修改函数的调用签名(也许是其他人的模块)

发生这种情况时,请使用函数装饰器

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)

@wrapsfrom functools 保持__name____doc__字符串的完整性。您还可以:

  • 从装饰器模块看,FunctionMaker但这应该是一种更可重用的方法。
  • 修改 newfoo 以允许不传递额外的非关键字变量。
于 2012-06-23T19:47:43.673 回答