argparse:在声明全局参数后无法获取subparser_name



我有一个带有一些子解析器的解析器。我设置了一个全局参数,用于所有子组件。以下是的相关片段

parser = argparse.ArgumentParser(prog="my_prog", add_help=False)
parser.add_argument('-d', '--debug', action='store_true', help='debug flag')
subparsers =  parser.add_subparsers(dest="subparser_name", help='some help notes')
parser_cmd1 = subparsers.add_parser('cmd1', parents=[parser])
parser_cmd1.add_argument('-f', '-foo', type=str, action=foo, required=False, help='foo command')
parser_cmd2 = subparsers.add_parser('cmd2', parents=[parser])
parser_cmd2.add_argument('-b', '-bar', type=str, action=bar, required=False, help='bar command')
args = parser.parse_args()
parser = args.subparser_name
print(args)
if args.debug:
logging.basicConfig(level=logging.INFO)
if parser == 'cmd1':
if args.foo:
//do foo stuff
if parser == 'cmd2':
if args.bar:
//do bar stuff

因此,您可以使用类似my_prog.py cmd1 -d -f inp_str的命令。问题是:subparser_name为None。打印输出(args(看起来有点像这个

Namespace(debug=True, foo="inp_str", subparser_name=None)

在添加全局调试参数之前,subpasser_name将是我运行的命令的名称,即"cmd1"或"cmd2"。现在,它是"无"。即使在子分析器的创建中添加了parents=[parser]。我该怎么解决这个问题?我怎么知道调用了哪个命令?

将公共args拆分为一个单独的ArgumentParser,然后将其用作子解析器的父级。此外,您的foo和bar选项是使用-foo和-bar指定的,whi应该是--foo和--bar。此外,您没有这些参数的默认值,因此例如,当未正确指定-f/--foo时,args.foo不存在。

这样效果更好:

import argparse
common_args = argparse.ArgumentParser(prog="my_prog", add_help=False)
common_args.add_argument('-d', '--debug', action='store_true', help='debug flag')
parser = argparse.ArgumentParser(prog="my_prog", add_help=True)
subparsers =  parser.add_subparsers(dest="subparser_name", help='some help notes')
parser_cmd1 = subparsers.add_parser('cmd1', parents=[common_args])
parser_cmd1.add_argument('-f', '--foo', type=str, default='', required=False, help='foo command')
parser_cmd2 = subparsers.add_parser('cmd2', parents=[common_args])
parser_cmd2.add_argument('-b', '--bar', type=str, default='', required=False, help='bar command')
args = parser.parse_args()
parser = args.subparser_name
print(args)
if args.debug:
logging.basicConfig(level=logging.INFO)
if parser == 'cmd1':
if args.foo:
#//do foo stuff
print( f"foo {args.foo}" )
if parser == 'cmd2':
if args.bar:
#//do bar stuff
print( f"bar {args.bar}" )

运行方式:

args.py cmd1 -f asd

输出:

Namespace(subparser_name='cmd1', debug=False, foo='asd')
foo asd

更新:

如果您希望能够使用例如args.py -d cmd1,则在创建parser时,指定parents=[common_args]

parser = argparse.ArgumentParser(prog="my_prog", add_help=True, parents=[common_args])

下次你问问题时,请确保你只将代码作为一个最小的可复制示例发布,即可以在不添加任何东西的情况下运行

子解析器的默认值优先于主解析器设置的任何值-默认值或用户输入。main对"cmd1"执行set the subparser_name,但子分析器将其更改回默认的None

虽然在测试用例中并不明显,但在两个级别上定义debug有相同的问题。子分析器的默认值覆盖在main中设置的任何内容。

通常,在主和子分析器中使用相同的dest不是一个好主意。标志可以相同,但dest应该不同——至少如果您想查看main设置的任何内容。

而使用主解析器作为子解析器的parent,只会造成混乱。

最新更新