argparse:声明全局参数后无法获得 subparser_name
argparse: unable to get subparser_name after declaring a global argument
我有一个带有一些子解析器的解析器。我设置了一个全局参数以用于所有子解析器。这是相关的片段
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。 print(args) 的输出看起来有点像这样
Namespace(debug=True, foo="inp_str", subparser_name=None)
在我添加全局调试参数之前,subparser_name 将是我 运行 命令的名称,即 'cmd1' 或 'cmd2'。现在,它是 'None'。即使在子解析器创建中添加了 parents=[parser] 。我怎样才能解决这个问题?我怎么知道调用了哪个命令?
子解析器的默认值优先于主解析器设置的任何值 - 默认值或用户输入。 main 将 set the subparser_name
改为 'cmd1',但 subparser 将其更改回默认值 None
。
虽然在您的测试用例中不明显,但在两个级别定义 debug
存在相同的问题。子解析器的默认值会覆盖主解析器中设置的任何内容。
一般来说,在主解析器和子解析器中使用相同的 dest
并不是一个好主意。标志可以相同,但 dest
应该不同 - 至少如果您想查看 main 设置的任何内容。
并且使用主解析器作为子解析器的 parent
,只是在自找麻烦。
将公共参数拆分为单独的 ArgumentParser,然后将其用作子解析器的父级。此外,您的 foo 和 bar 选项是使用 -foo 和 -bar 指定的,而应该是 --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])
下次您提问时,请确保您只post 将代码作为最小的可重现示例 - 即可以 运行 不添加任何内容
我有一个带有一些子解析器的解析器。我设置了一个全局参数以用于所有子解析器。这是相关的片段
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。 print(args) 的输出看起来有点像这样
Namespace(debug=True, foo="inp_str", subparser_name=None)
在我添加全局调试参数之前,subparser_name 将是我 运行 命令的名称,即 'cmd1' 或 'cmd2'。现在,它是 'None'。即使在子解析器创建中添加了 parents=[parser] 。我怎样才能解决这个问题?我怎么知道调用了哪个命令?
子解析器的默认值优先于主解析器设置的任何值 - 默认值或用户输入。 main 将 set the subparser_name
改为 'cmd1',但 subparser 将其更改回默认值 None
。
虽然在您的测试用例中不明显,但在两个级别定义 debug
存在相同的问题。子解析器的默认值会覆盖主解析器中设置的任何内容。
一般来说,在主解析器和子解析器中使用相同的 dest
并不是一个好主意。标志可以相同,但 dest
应该不同 - 至少如果您想查看 main 设置的任何内容。
并且使用主解析器作为子解析器的 parent
,只是在自找麻烦。
将公共参数拆分为单独的 ArgumentParser,然后将其用作子解析器的父级。此外,您的 foo 和 bar 选项是使用 -foo 和 -bar 指定的,而应该是 --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])
下次您提问时,请确保您只post 将代码作为最小的可重现示例 - 即可以 运行 不添加任何内容