Python argparse,运行一个或多个子命令
我正在尝试写一个程序,能够执行多个子命令。argparse模块非常有用,但我觉得它在指定多个子命令方面有些不足。比如说,如果我有以下代码:
parser = argparse.ArgumentParser(prog='My Prog')
sub_parsers = parser.add_subparsers()
subcommand_a = sub_parsers.add_parser('subcommand_a', help='a help')
subcommand_a.add_argument('req1', help='required argument 1 help')
subcommand_a.add_argument('--opt1', help='option 1 help')
subcommand_a.add_argument('--opt2', nargs='+', help='option 2 help')
subcommand_b = sub_parsers.add_parser('subcommand_b', help='b help')
subcommand_b.add_argument('req1', help='required argument 1 help')
subcommand_b.add_argument('--opt1', help='option 1 help')
subcommand_b.add_argument('--opt2', help='option 2 help')
subcommand_b.add_argument('--opt3', nargs='+', help='option 3 help')
parser.parse_args()
我不能在命令行中同时指定subcommand_a和subcommand_b。我一次只能选择其中一个。我想这可能需要自定义一个动作,或者甚至可能需要对argparse进行子类化,但我不太确定从哪里开始。我希望能够像下面这样调用这个程序:
./prog.py subcommand_a FOO --opt1=bar --opt2 1 2 3 -- subcommand_b BAR --opt1='foo' --opt3 a b c --
有什么想法吗?
2 个回答
0
我做了一些测试,发现把子命令改成其他字符串就能正常工作。如果你使用:
parser = argparse.ArgumentParser(prog='My Prog')
sub_parsers = parser.add_subparsers()
subcommand_a = sub_parsers.add_parser('subcommand_a', help='a help')
subcommand_a.add_argument('req1', help='required argument 1 help')
subcommand_a.add_argument('--opt1', help='option 1 help')
subcommand_a.add_argument('--opt2', nargs='+' help='option 2 help')
subcommand_b = sub_parsers.add_parser('subcommand_b', help='b help')
subcommand_b.add_argument('req1', help='required argument 1 help')
subcommand_b.add_argument('--opt3', help='option 1 help')
subcommand_b.add_argument('--opt4', help='option 2 help')
subcommand_b.add_argument('--opt5', nargs='+', help='option 3 help')
parser.parse_args()
这样就可以了。
我查了一下资料,没找到有相同字符串的子命令。文档的概述里也没有提到这个。我猜这可能是个限制(可能是故意的)或者是个bug。也许你可以在这个链接里查看源代码。
2
你的问题其实和几个月前问的一个问题差不多。
那个人想要多次调用同一个子命令,但问题是一样的——如何处理多个 subparsers
参数。
那里的解决办法是,要么在传入命令之前先把命令行拆分成几部分,分别解析;要么从一次解析中收集“未使用”的部分,以便在第二次或第三次使用。
这里有个对你代码的小改动,可以返回两个命令:
import argparse
parser = argparse.ArgumentParser(prog='My Prog')
sub_parsers = parser.add_subparsers(dest='cmd')
subcommand_a = sub_parsers.add_parser('subcommand_a', help='a help')
subcommand_a.add_argument('req1', help='required argument 1 help')
subcommand_a.add_argument('--opt1', help='option 1 help')
subcommand_a.add_argument('--opt2', nargs=3, help='option 2 help')
subcommand_b = sub_parsers.add_parser('subcommand_b', help='b help')
subcommand_b.add_argument('req1', help='required argument 1 help')
subcommand_b.add_argument('--opt1', help='option 1 help')
subcommand_b.add_argument('--opt2', help='option 2 help')
subcommand_b.add_argument('--opt3', nargs=3, help='option 3 help')
argv = "subcommand_a FOO --opt1=bar --opt2 1 2 3 subcommand_b BAR --opt1=foo --opt3 a b c"
rest = argv.split()
while rest:
[args, rest] = parser.parse_known_args(rest)
print args
print rest
这段代码会打印:
Namespace(cmd='subcommand_a', opt1='foo', opt2=['1', '2', '3'], req1='FOO')
['subcommand_b', 'BAR', '--opt3', 'a', 'b', 'c']
Namespace(cmd='subcommand_b', opt1=None, opt2=None, opt3=['a', 'b', 'c'], req1='BAR')
[]
我去掉了 '--'
(请看我其他回答的结尾)
我把 opt2
和 opt3
改成接受三个参数,而不是用可变参数 +
。用 +
的话,程序就不知道 opt2
的列表在哪儿结束,下一条命令从哪儿开始。
另外,不同的命令要有不同的可选参数(标志)。注意,第一个 opt1
最终得到了第二个值 'foo',这就导致第二个命令没有值可用。可以去看其他讨论,了解这些问题和解决办法。