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

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

提问人:joel 提问时间:6/27/2017 最后编辑:joel 更新时间:7/10/2020 访问量:6710

问:

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

例如,如果我们从一个包含以下行的模块 mymod 开始template_kvps = {'a': 1, 'b': 2}

我只能:

import mymod

def func(**kwargs):
    pass

func(**mymod.template_kvps)

然后我就可以访问我的内部.但我希望能够以最小的开销传递不同的值。template_kvpsfunc()a

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

理想情况下,我想重新定义,以便我可以像 sth 一样做 sth,但事实上,Python 错误与重复参数有关。funcfunc(**mymod.template_kvps, a=3)

顺便说一句,我很高兴考虑更改 .template_kvps

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

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

func_template(a=3)
python 字典 关键字参数

评论

0赞 Moses Koledoye 6/27/2017
我想知道为什么我们都在为一行额外的代码而烦恼。我不明白这是怎么一团糟。
5赞 Artyer 6/27/2017
如何工作?不应该吗?func(mymod.template_kvps)func(**mymod.template_kvps)
0赞 joel 6/28/2017
@Artyer,是的,我的错误,纠正了

答:

0赞 Carl Shiles 6/27/2017 #1

你可以有一个函数来更新你想要更改的任何值。(已编辑,因此不会修改原始词典。

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}))

评论

0赞 Carl Shiles 6/29/2017
谢谢,简单多了。
0赞 hspandher 6/27/2017 #2

这应该有效

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

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

5赞 Artyer 6/28/2017 #3

你可以像这样在一行中做到这一点:

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

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

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

func(**mymod.template_kvps_without_a, a=3)
14赞 a_guest 6/28/2017 #4

为此,可以使用内置类型。它接受另一个字典作为参数,并接受其他键值对作为关键字参数(优先于另一个字典中的值)。dict

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

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

这样,就不需要更改函数的签名,您可以根据需要更新/添加任意数量的键值对。

1赞 Clarus 6/28/2017 #5

我会考虑函数装饰器,因为这会使语法与您要求的语法基本相同。实现如下所示:

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 )
0赞 Jared Goguen 6/28/2017 #6

我会将模板参数更改为位置参数,并将键覆盖为 .**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)