如何在 Python 2.x 中合并两个 argparse 命名空间?

jua*_*ngo 5 python-2.x

我想argparse.Namespace在 Python 2.x 中合并 2 个对象。

在 python 3.x 中,我可以做这样的事情:

from argparse import Namespace

# The 2 initial objects
options_foo = Namespace(foo="foo")
options_bar = Namespace(bar="bar")

# the merged object
options_baz = Namespace(**vars(options_foo), **vars(options_bar))
Run Code Online (Sandbox Code Playgroud)

并得到:

print(options_baz)
# Namespace(foo="foo", bar="bar")
Run Code Online (Sandbox Code Playgroud)

但在 python 2.x 中我不能。我收到以下错误。

SyntaxError: invalid syntax
Run Code Online (Sandbox Code Playgroud)

有没有简单的方法来实现这一目标?

Cha*_*ker 5

这是一个合并两个参数的函数:

def merge_args_safe(args1: Namespace, args2: Namespace) -> Namespace:
    """
    Merges two namespaces but throws an error if there are keys that collide.

    ref: /sf/ask/3929558461/
    :param args1:
    :param args2:
    :return:
    """
    # - the merged args
    # The vars() function returns the __dict__ attribute to values of the given object e.g {field:value}.
    args = Namespace(**vars(args1), **vars(args2))
    return args
Run Code Online (Sandbox Code Playgroud)

测试

def merge_args_test():
    args1 = Namespace(foo="foo", collided_key='from_args1')
    args2 = Namespace(bar="bar", collided_key='from_args2')

    args = merge_args(args1, args2)
    print('-- merged args')
    print(f'{args=}')
Run Code Online (Sandbox Code Playgroud)

输出:

Traceback (most recent call last):
  File "/Applications/PyCharm.app/Contents/plugins/python/helpers/pydev/pydevd.py", line 1483, in _exec
    pydev_imports.execfile(file, globals, locals)  # execute the script
  File "/Applications/PyCharm.app/Contents/plugins/python/helpers/pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile
    exec(compile(contents+"\n", file, 'exec'), glob, loc)
  File "/Users/brando/ultimate-utils/ultimate-utils-proj-src/uutils/__init__.py", line 1202, in <module>
    merge_args_test()
  File "/Users/brando/ultimate-utils/ultimate-utils-proj-src/uutils/__init__.py", line 1192, in merge_args_test
    args = merge_args(args1, args2)
  File "/Users/brando/ultimate-utils/ultimate-utils-proj-src/uutils/__init__.py", line 1116, in merge_args
    args = Namespace(**vars(args1), **vars(args2))
TypeError: argparse.Namespace() got multiple values for keyword argument 'collided_key'
python-BaseException
Run Code Online (Sandbox Code Playgroud)

你可以在这个库中找到它:https ://github.com/brando90/ultimate-utils


如果您想解决冲突,请执行以下操作:

def merge_two_dicts(starting_dict: dict, updater_dict: dict) -> dict:
    """
    Starts from base starting dict and then adds the remaining key values from updater replacing the values from
    the first starting/base dict with the second updater dict.

    For later: how does d = {**d1, **d2} replace collision?

    :param starting_dict:
    :param updater_dict:
    :return:
    """
    new_dict: dict = starting_dict.copy()   # start with keys and values of starting_dict
    new_dict.update(updater_dict)    # modifies starting_dict with keys and values of updater_dict
    return new_dict

def merge_args(args1: Namespace, args2: Namespace) -> Namespace:
    """

    ref: /sf/ask/3929558461/
    :param args1:
    :param args2:
    :return:
    """
    # - the merged args
    # The vars() function returns the __dict__ attribute to values of the given object e.g {field:value}.
    merged_key_values_for_namespace: dict = merge_two_dicts(vars(args1), vars(args2))
    args = Namespace(**merged_key_values_for_namespace)
    return args
Run Code Online (Sandbox Code Playgroud)

测试:

def merge_args_test():
    args1 = Namespace(foo="foo", collided_key='from_args1')
    args2 = Namespace(bar="bar", collided_key='from_args2')

    args = merge_args(args1, args2)
    print('-- merged args')
    print(f'{args=}')
    assert args.collided_key == 'from_args2', 'Error in merge dict, expected the second argument to be the one used' \
                                                 'to resolve collision'
Run Code Online (Sandbox Code Playgroud)

  • @juanesarango,双星语法是有效的Python2。我已经完全重新回答了您的问题,以了解促使您发帖的基本语法错误。 (2认同)

Zac*_*ung 1

我主要重新考虑了这个答案,因为我没有完全阅读和理解你的问题......

确实,这一行在Python3中有效,在Python2中无效:

options_baz = Namespace(**vars(options_foo), **vars(options_bar))
Run Code Online (Sandbox Code Playgroud)

当我们查看错误时,我们发现这是,Python2无法接受的逗号():

options_baz = Namespace(**vars(options_foo), **vars(options_bar))
Run Code Online (Sandbox Code Playgroud)

因此,我们避免将两组选项传递给Namespace()初始值设定项:

...

dict_baz = vars(options_foo)
dict_baz.update(vars(options_bar))

# the merged object
options_baz = Namespace(**dict_baz)

print(options_baz)
Run Code Online (Sandbox Code Playgroud)

我们得到:

Namespace(bar='bar', foo='foo')
Run Code Online (Sandbox Code Playgroud)

在另一个答案中,您指出双星 ( **) 语法无效,但这绝对是有效的语法。我们可以看到早在Python 2.2就提到过它:

如果语法**expression出现在函数调用中, expression则必须计算为字典(的子类),...

一直都是那个逗号。

  • 即使对于 Python 3,涉及字典“update”方法的解决方案也更好,因为它支持出现在两个命名空间中的键。第二个命名空间优先于第一个命名空间。(在同样的情况下,`Namespace(**vars(foo), **vars(bar))`会引发异常。) (2认同)