覆盖 Python 中的关键字参数
Override a keyword argument in Python
Python版本:3.10.0
我有多个函数使用相同的参数,大部分也有相同的值,所以我决定使用关键字参数来减少提供给函数的参数数量。
但是,现在我 运行 进入了这个问题:如果我想用自定义值覆盖一些关键字参数,而不改变 'global defaults' 怎么办?
使用一个简化的例子:
def func(arg1, arg2, **kwargs):
print(f"Received: {arg1} {arg2} {kwargs}")
print(f"Special: {kwargs.get('special')}")
def func2(arg1, arg2, **kwargs):
print(f"Received: {arg1} {arg2} {kwargs}")
print(f"Special: {kwargs.get('special')}")
common = {
'param1': 10,
'param2': True,
'special': "SPECIAL_DEFAULT"
}
if __name__ == '__main__':
func("test", "some-value", **common)
func2(99, None, **common)
# For example, for this call, I want to override one of the common arguments with a different value
# Without altering var common that is used globally
# However, it throws TypeError because 'special' is defined in multiple places now
func("test", "some-another-value", special="SOMETHING_ELSE", **common)
我已将所有常用关键字参数存储在一个字典中,该字典提供给所有使用常用参数的函数。
但是,当我尝试覆盖一些关键字参数时,我收到了这个错误:
Traceback (most recent call last):
line 24, in <module>
func("test", "some-another-value", special="SOMETHING_ELSE", **common)
TypeError: __main__.func() got multiple values for keyword argument 'special'
意思是 Python 无法决定它会使用哪个提供的值。
解决这个问题的最干净(最优雅)的方法是什么?
def func(arg1, arg2, **kwargs):
print(f"Received: {arg1} {arg2} {kwargs}")
print(f"Special: {kwargs.get('special')}")
common = {"param1": 10, "param2": True, "special": "SPECIAL_DEFAULT"}
special_params = {**common, "special": "SOMETHING_ELSE"}
if __name__ == "__main__":
func("test", "some-value", **common)
func(99, None, **common)
func("test", "some-another-value", **special_params)
What would be the cleanest (most elegant) way to overcome this issue?
在这种情况下,我会使用 functools.partial
(来自标准库中的 functools
模块)考虑以下简单示例
import functools
def volume(**kwargs):
return kwargs["x"]*kwargs["y"]*kwargs["z"]
volume = functools.partial(volume, x=1, y=1, z=1)
print(volume()) # 1
print(volume(z=5)) # 5
print(volume(x=2,y=3,z=4)) # 24
functools.partial
提供部分对象,其行为类似于提供给它的具有设置默认值的函数。
您可以使用更新后的值创建新字典:
def func(arg1, arg2, **kwargs):
print(f"Received: {arg1} {arg2} {kwargs}")
print(f"Special: {kwargs.get('special')}")
def func2(arg1, arg2, **kwargs):
print(f"Received: {arg1} {arg2} {kwargs}")
print(f"Special: {kwargs.get('special')}")
common = {
'param1': 10,
'param2': True,
'special': "SPECIAL_DEFAULT"
}
if __name__ == '__main__':
func("test", "some-value", **common)
func2(99, None, **common)
spcl = dict(common)
spcl['special'] = "SOMETHING_ELSE"
func("test", "some-another-value", **spcl)
print(common)
print(spcl)
输出:
Received: test some-value {'param1': 10, 'param2': True, 'special': 'SPECIAL_DEFAULT'}
Special: SPECIAL_DEFAULT
Received: 99 None {'param1': 10, 'param2': True, 'special': 'SPECIAL_DEFAULT'}
Special: SPECIAL_DEFAULT
Received: test some-another-value {'param1': 10, 'param2': True, 'special': 'SOMETHING_ELSE'}
Special: SOMETHING_ELSE
{'param1': 10, 'param2': True, 'special': 'SPECIAL_DEFAULT'}
{'param1': 10, 'param2': True, 'special': 'SOMETHING_ELSE'}
>>> foo = {'bar': 'baz'}
>>> {**foo, 'bar': 42}
{'bar': 42}
>>> {'bar': 42, **foo}
{'bar': 'baz'}
所以:
func("test", "some-another-value", **{**common, "special": "SOMETHING_ELSE"})
Python版本:3.10.0
我有多个函数使用相同的参数,大部分也有相同的值,所以我决定使用关键字参数来减少提供给函数的参数数量。
但是,现在我 运行 进入了这个问题:如果我想用自定义值覆盖一些关键字参数,而不改变 'global defaults' 怎么办?
使用一个简化的例子:
def func(arg1, arg2, **kwargs):
print(f"Received: {arg1} {arg2} {kwargs}")
print(f"Special: {kwargs.get('special')}")
def func2(arg1, arg2, **kwargs):
print(f"Received: {arg1} {arg2} {kwargs}")
print(f"Special: {kwargs.get('special')}")
common = {
'param1': 10,
'param2': True,
'special': "SPECIAL_DEFAULT"
}
if __name__ == '__main__':
func("test", "some-value", **common)
func2(99, None, **common)
# For example, for this call, I want to override one of the common arguments with a different value
# Without altering var common that is used globally
# However, it throws TypeError because 'special' is defined in multiple places now
func("test", "some-another-value", special="SOMETHING_ELSE", **common)
我已将所有常用关键字参数存储在一个字典中,该字典提供给所有使用常用参数的函数。
但是,当我尝试覆盖一些关键字参数时,我收到了这个错误:
Traceback (most recent call last):
line 24, in <module>
func("test", "some-another-value", special="SOMETHING_ELSE", **common)
TypeError: __main__.func() got multiple values for keyword argument 'special'
意思是 Python 无法决定它会使用哪个提供的值。
解决这个问题的最干净(最优雅)的方法是什么?
def func(arg1, arg2, **kwargs):
print(f"Received: {arg1} {arg2} {kwargs}")
print(f"Special: {kwargs.get('special')}")
common = {"param1": 10, "param2": True, "special": "SPECIAL_DEFAULT"}
special_params = {**common, "special": "SOMETHING_ELSE"}
if __name__ == "__main__":
func("test", "some-value", **common)
func(99, None, **common)
func("test", "some-another-value", **special_params)
What would be the cleanest (most elegant) way to overcome this issue?
在这种情况下,我会使用 functools.partial
(来自标准库中的 functools
模块)考虑以下简单示例
import functools
def volume(**kwargs):
return kwargs["x"]*kwargs["y"]*kwargs["z"]
volume = functools.partial(volume, x=1, y=1, z=1)
print(volume()) # 1
print(volume(z=5)) # 5
print(volume(x=2,y=3,z=4)) # 24
functools.partial
提供部分对象,其行为类似于提供给它的具有设置默认值的函数。
您可以使用更新后的值创建新字典:
def func(arg1, arg2, **kwargs):
print(f"Received: {arg1} {arg2} {kwargs}")
print(f"Special: {kwargs.get('special')}")
def func2(arg1, arg2, **kwargs):
print(f"Received: {arg1} {arg2} {kwargs}")
print(f"Special: {kwargs.get('special')}")
common = {
'param1': 10,
'param2': True,
'special': "SPECIAL_DEFAULT"
}
if __name__ == '__main__':
func("test", "some-value", **common)
func2(99, None, **common)
spcl = dict(common)
spcl['special'] = "SOMETHING_ELSE"
func("test", "some-another-value", **spcl)
print(common)
print(spcl)
输出:
Received: test some-value {'param1': 10, 'param2': True, 'special': 'SPECIAL_DEFAULT'}
Special: SPECIAL_DEFAULT
Received: 99 None {'param1': 10, 'param2': True, 'special': 'SPECIAL_DEFAULT'}
Special: SPECIAL_DEFAULT
Received: test some-another-value {'param1': 10, 'param2': True, 'special': 'SOMETHING_ELSE'}
Special: SOMETHING_ELSE
{'param1': 10, 'param2': True, 'special': 'SPECIAL_DEFAULT'}
{'param1': 10, 'param2': True, 'special': 'SOMETHING_ELSE'}
>>> foo = {'bar': 'baz'}
>>> {**foo, 'bar': 42}
{'bar': 42}
>>> {'bar': 42, **foo}
{'bar': 'baz'}
所以:
func("test", "some-another-value", **{**common, "special": "SOMETHING_ELSE"})