Python argparse:如何分别获取参数组的命名空间对象?

Python argparse : How can I get Namespace objects for argument groups separately?

我有一些命令行参数分组如下:

cmdParser = argparse.ArgumentParser()
cmdParser.add_argument('mainArg')

groupOne = cmdParser.add_argument_group('group one')
groupOne.add_argument('-optA')
groupOne.add_argument('-optB')

groupTwo = cmdParser.add_argument_group('group two')
groupTwo.add_argument('-optC')
groupTwo.add_argument('-optD')

我如何解析以上内容,从而得到三个不同的命名空间对象?

global_args - containing all the arguments not part of any group
groupOne_args - containing all the arguments in groupOne
groupTwo_args - containing all the arguments in groupTwo

谢谢!

argparse 中没有任何内容旨在做到这一点。

就其价值而言,parser 从两个参数组开始,一个显示为 positionals,另一个显示为 optionals(我忘记了确切的标题)。所以在你的例子中实际上会有 4 个组。

解析器在格式化帮助时仅使用参数组。为了解析,所有参数都放在主 parser._actions 列表中。在解析过程中,解析器只传递一个命名空间 object.

您可以使用不同的参数集定义单独的解析器,并使用 parse_known_args 调用每个解析器。使用 optionals(标记的)参数比使用 positionals 效果更好。它会分散你的帮助。

我在其他 SO 问题中探索了一本小说 Namespace class,它可以基于某种点缀 dest(如 group1.optAgroup2.optC,等等)。我不记得我是否必须自定义 Action classes。

基本点是,当将值保存到命名空间、解析器或实际上 Action(参数)object 时:

setattr(namespace, dest, value)

那(和 getattr/hasattr)是解析器对 namespace 的全部期望。默认的 Namespace class 很简单,只不过是一个普通的 object subclass。但它可以更详细。

你可以这样做:

import argparse
parser = argparse.ArgumentParser()

group1 = parser.add_argument_group('group1')
group1.add_argument('--test1', help="test1")

group2 = parser.add_argument_group('group2')
group2.add_argument('--test2', help="test2")

args = parser.parse_args('--test1 one --test2 two'.split())

arg_groups={}

for group in parser._action_groups:
    group_dict={a.dest:getattr(args,a.dest,None) for a in group._group_actions}
    arg_groups[group.title]=argparse.Namespace(**group_dict)

这将为您提供正常的参数,以及包含每个添加组的名称空间的字典 arg_groups。

(改编自

我一直在寻找解决方案,
我想我终于明白了。
所以我就把它放在这里...

from argparse import ArgumentParser

def _parse_args():
    parser = ArgumentParser()
    parser.add_argument('-1', '--flag-1', action='store_true', default=False)
    parser.add_argument('-2', '--flag-2', action='store_true', default=False)
    parser.add_argument('-3', '--flag-3', action='store_true', default=False)

    args, unknown = parser.parse_known_args()
    print(f"args        : {args}")
    print(f"unknown     : {unknown}")

    hidden = ArgumentParser(add_help=False)
    hidden.add_argument('-d', '--debug', action='store_true', default=False)
    hidden_args = hidden.parse_args(unknown)
    print(f"hidden_args : {hidden_args}")

if __name__ == "__main__":
    _parse_args()

结果:
显示帮助:

ubuntu → playAround $ ./test.py -h
usage: test.py [-h] [-1] [-2] [-3]

optional arguments:
  -h, --help    show this help message and exit
  -1, --flag-1
  -2, --flag-2
  -3, --flag-3

带有调试标志:

ubuntu → playAround $ ./test.py -d
args        : Namespace(flag_1=False, flag_2=False, flag_3=False)
unknown     : ['-d']
hidden_args : Namespace(debug=True)

带有标志 1 和 2:

ubuntu → playAround $ ./test.py -12
args        : Namespace(flag_1=True, flag_2=True, flag_3=False)
unknown     : []
hidden_args : Namespace(debug=False)

带有标志 1 和 2 以及调试:

ubuntu → playAround $ ./test.py -12 -d
args        : Namespace(flag_1=True, flag_2=True, flag_3=False)
unknown     : ['-d']
hidden_args : Namespace(debug=True)

你唯一不能用这个方法做的是将调试短标志一起传递给其他短标志:

ubuntu → playAround $ ./test.py -12d
usage: test.py [-h] [-1] [-2] [-3]
test.py: error: argument -2/--flag-2: ignored explicit argument 'd'

这是一个简单的方法,它在定义每个组后调用 parse_known_args() 方法以分别获取这些参数的名称。

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('mainArg')
global_names = set(vars(parser.parse_known_args()[0]).keys())

group1 = parser.add_argument_group('group 1')
group1.add_argument('-optA')
group1.add_argument('-optB')
group1_names = set(vars(parser.parse_known_args()[0]).keys()) - global_names

group2 = parser.add_argument_group('group 2')
group2.add_argument('-optC')
group2.add_argument('-optD')
group2_names = set(vars(parser.parse_known_args()[0]).keys()) - global_names - group1_names

args = parser.parse_args()
global_args = argparse.Namespace(**dict((k, v) for k, v in vars(args).items() if k in global_names))
group1_args = argparse.Namespace(**dict((k, v) for k, v in vars(args).items() if k in group1_names))
group2_args = argparse.Namespace(**dict((k, v) for k, v in vars(args).items() if k in group2_names))

print(global_args)
print(group1_args)
print(group2_args)

例如python args.py hi -optA fooA -optB fooB -optC fooC -optD fooD 将输出:

Namespace(mainArg='hi')
Namespace(optA='fooA', optB='fooB')
Namespace(optC='fooC', optD='fooD')