在方法调用参数中,如何覆盖解压字典的关键字参数?
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)
为了方便函数调用(通过字典和关键字参数),我正在尝试使用模板关键字参数,同时能够覆盖一些参数。
例如,如果我们从包含行 template_kvps = {'a': 1, 'b': 2}
我只能:
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)