在方法调用参数中,如何覆盖解压字典的关键字参数?

In method call args, how to override keyword argument of unpacked dict?

为了方便函数调用(通过字典和关键字参数),我正在尝试使用模板关键字参数,同时能够覆盖一些参数。

例如,如果我们从包含行 template_kvps = {'a': 1, 'b': 2}

的模块 mymod 开始

我只能:

import mymod

def func(**kwargs):
    pass

func(**mymod.template_kvps)

然后我可以在 func() 内访问我的 template_kvps。但是我希望能够以最小的开销为 a 传递不同的值。

我所能想到的就是在函数调用之前更改字典:kvps = {**template_kvps, 'a': 3}; func(**kvps),但那是行数的两倍,我在大约 1000 个测试脚本中的每一个中都多次使用这个函数。

理想情况下,我想重新定义 func,这样我就可以像 func(**mymod.template_kvps, a=3) 那样做某事,但实际上,Python 出现一些关于重复参数的错误。

顺便说一句,我很乐意考虑更改 template_kvps 的格式。

编辑(将在某个时候回答)我可以改用包装方法

def func_template(a=1, b=2):
    func(a, b)

func_template(a=3)

您可以有一个函数来更新您想要更改的任何值。 (经过编辑,不修改原始词典。)

import mymod

def replace(dict1, dict2):
  ans = dict1.copy()
  ans.update(dict2)
  return ans

def func(**kwargs):
  pass

func(replace(mymod.template_kvps, {'a':3}))

这应该有效

func(a=3, **{key: value for key, value in mymod.template_kvps.items() if key != 'a')})

但是我建议再写一行代码,不要混淆它。

你可以像这样在一行中完成:

func(**{**mymod.template_kvps, 'a': 3})

但这乍一看可能并不明显,但与您之前所做的一样明显。

我建议使用多个模板(例如 template_kvps_without_a),但这取决于您的具体用例:

func(**mymod.template_kvps_without_a, a=3)

您可以为此目的使用内置的 dict 类型。它接受另一个字典作为参数和额外的键值对作为关键字参数(优先于另一个字典中的值)。

因此您可以通过 dict(template_vars, a=1) 创建一个更新的字典。

您可以将此字典展开为关键字参数:func(**dict(...)).

这样就不需要更改函数的签名,您可以 update/add 任意多的键值对。

我会考虑使用函数装饰器,因为它可以使语法与您要求的基本相同。实现看起来像:

def combine(func):
  def wrapper(*args, **kwargs):
    fargs = {}
    if args and isinstance( args[0], dict ):
      fargs = args[0].copy()
    fargs.update(kwargs)
    return func(**fargs)
  return wrapper


@combine
def funky(**kwargs):
  for k,v in kwargs.iteritems():
    print "%s: %s" % (k, v)

# All of these work as expected
funky( {'a': 1, 'b': 2}, a=3 )
funky( {'a': 1, 'b': 2} )
funky( a=3 )

我将模板参数更改为位置参数,键将被覆盖为 **kwargs

def func(template_dict, **kwargs):
    updated_dict = {**template_dict, **kwargs}
    return updated_dict

print(func({'a':1, 'b':2}, a=3)) # {'a': 3, 'b': 2}

请注意,双重解包语法需要 Python 3.5+。在旧版本上,使用:

updated_dict = template_dict.copy()
updated_dict.update(kwargs)