我试图在函数调用中使用模板关键字args(通过dict和关键字参数),同时能够覆盖一些参数。
例如,如果我们从包含行template_kvps = {'a': 1, 'b': 2}
我可以:
import mymod
def func(**kwargs):
pass
func(**mymod.template_kvps)
然后我可以在template_kvps
内访问我的func()
。但我希望能够以最小的开销为a
传递不同的值。
所有我能想到的是在函数调用之前更改字典:kvps = {**template_kvps, 'a': 3}; func(**kvps)
,但这是行数的两倍,我在每个周围使用此函数几次1000个测试脚本。
理想情况下,我希望重新定义func
以便我可以像func(**mymod.template_kvps, a=3)
那样做,但事实上,Python错误与重复参数有关。
btw我很高兴考虑更改template_kvps
的格式。
注意稍后添加我的问题有一些很好的答案(而且我已经接受了我认为对我所问的最佳答案),但我认为我'我问了一件坏事。我建议这是一个设计问题,如果我想要这样的默认参数,我认为最好用默认参数而不是模板字典创建一个包装器方法,如下所示:
def func_template(a=1, b=2):
func(a, b)
func_template(a=3)
答案 0 :(得分:6)
您可以使用内置dict
类型来实现此目的。它接受另一个dict作为参数,并接受其他键值对作为关键字参数(优先于其他dict中的值)。
因此,您可以通过dict(template_vars, a=1)
创建更新的字典。
您可以将此dict展开为关键字参数:func(**dict(...))
。
就像那样,无需更改功能的签名,您可以根据需要更新/添加任意数量的键值对。
答案 1 :(得分:1)
你可以这样做一行:
func(**{**mymod.template_kvps, 'a': 3})
但乍一看这可能并不明显,但与你之前所做的一样明显。
我建议使用多个模板(例如template_kvps_without_a
),但这取决于您的具体用例:
func(**mymod.template_kvps_without_a, a=3)
答案 2 :(得分:1)
我会考虑函数装饰器,因为它保持语法与您请求的大致相同。实现看起来像:
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 )
答案 3 :(得分:0)
您可以使用更新要更改的任何值的函数。 (编辑以便不修改原始字典。)
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}))
答案 4 :(得分:0)
这应该有效
func(a=3, **{key: value for key, value in mymod.template_kvps.items() if key != 'a')})
但是我建议写另一行代码,而不是混淆它。
答案 5 :(得分:0)
我将模板参数更改为位置参数,并将键覆盖为**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)