argparse有多个subparsers和positionals

时间:2018-05-24 09:02:50

标签: python python-3.x

我们假设我有一个脚本select_libs.py,它允许您选择在某些构建过程中包含哪些库。运行此脚本时,我希望能够指定库名称,分支和版本。以下是一些用例。

  • select_libs.py
    • 未定义位置时使用脚本默认值。
  • select_libs.py opencv stable 3.4.1
  • select_libs.py opencv stable 3.4.1 boost development 1.67.0

所以我想象一下这么简单:

import argparse

branches = ["legacy", "stable", "development"]

parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(help='lib configuration')

opencv_parser = subparsers.add_parser("opencv")
opencv_parser.add_argument("opencv_build", choices=branches)
opencv_parser.add_argument("opencv_version", type=str)

boost_parser = subparsers.add_parser("boost")
boost_parser.add_argument("boost_build", choices=branches)
boost_parser.add_argument("boost_version",type=str)

cmd_options = parser.parse_args()

前两个用例都有效,但第三个:

select_libs.py opencv stable 3.4.1 boost development 1.67.0

产生此错误:

error: unrecognized arguments: boost development 1.67.0

在我的脑海中,这应该有效,因为每个解析器都有两个位置参数,因此它应该知道boost不是opencv的参数并相应地触发boost解析器。显然我错了,但我错过了什么,如何让它按预期工作(如果可能的话)?

我目前的Python版本是3.5.2

1 个答案:

答案 0 :(得分:1)

Argparse不适合这种事情。 add_subparsers假设将使用正好一个子命令,因此如果您尝试同时设置opencvboost,则会引发错误。除此之外,argparse没有与其他参数相关联的参数概念。

选项1

如果您不介意使用关键字选项而非位置选项,则可以使用this answer中的解决方案:

argv = '-l opencv -b stable -v 3.4.1 -l boost -b development -v 1.67.0'.split()

parser = argparse.ArgumentParser()
parent = parser.add_argument('-l', '--lib', choices=['opencv', 'boost'], action=ParentAction)

parser.add_argument('-b', '--build', action=ChildAction, parent=parent)
parser.add_argument('-v', '--version', action=ChildAction, parent=parent)

args = parser.parse_args(argv)
print(args)
# output:
# Namespace(lib=OrderedDict([('opencv', Namespace(build='stable',
#                                                 version='3.4.1')),
#                            ('boost', Namespace(build='development',
#                                                version='1.67.0'))]))

选项2

使用nargs参数使其成为位置和命名参数的混合:

argv = '-l opencv stable 3.4.1 -l boost development 1.67.0'.split()

parser = argparse.ArgumentParser()
parent = parser.add_argument('-l', '--lib', nargs=3, action='append')

args = parser.parse_args(argv)
print(args)
# output:
# Namespace(lib=[['opencv', 'stable', '3.4.1'],
#                ['boost', 'development', '1.67.0']])

选项3

手动解析参数:

argv = 'opencv stable 3.4.1 boost development 1.67.0'.split()

args = {}
argv_itr = iter(argv)
for lib in argv_itr:
    args[lib] = {'build': next(argv_itr),
                 'version': next(argv_itr)}

print(args)
# output:
# {'opencv': {'build': 'stable',
#             'version': '3.4.1'},
#  'boost': {'build': 'development',
#            'version': '1.67.0'}}