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

興味深い質問です。実生活のほとんどの人は@AshwiniChaudharyアプローチを使用していると思います。

私は@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 に答える