你如何让 argparse 选择一个默认的子解析器? [英] How do you get argparse to choose a default subparser?
问题描述
我在 script.py
中有以下代码:
I have the following code in script.py
:
import argparse
parser = argparse.ArgumentParser()
sp = parser.add_subparsers(dest='command')
sp.default = 'a'
a_parser = sp.add_parser('a')
b_parser = sp.add_parser('b')
a_parser.add_argument('--thing', default='thing')
b_parser.add_argument('--nothing', default='nothing')
args = parser.parse_args()
print(args)
我可以用三种不同的方式来称呼它:
I can call this three different ways:
$ python3 script.py
Namespace(command='a')
$ python3 script.py a
Namespace(command='a', thing='thing')
$ python3 script.py b
Namespace(command='b', nothing='nothing')
这只有一个问题:我想要的是,如果我在命令行上提供零个参数,a_parser
将成为结束解析和做事.显然不是,sp.default
只是设置 command='a'
,不是我所期望的,也就是说,哦,是的,用户没有在命令行上提供任何参数,但我知道这应该由 a_parser
处理.这是 Namespace(command='a', thing='thing')
!"
There's only one problem with this: what I want is that if I provide zero arguments on the command line is for a_parser
to be the one that ends out parsing and doing stuff. Clearly it's not, the sp.default
is just setting command='a'
, not what I expect, which is to say, "Oh yeah, the user didn't provide any arguments on the command line, but I know that this should be processed by a_parser
. Here's Namespace(command='a', thing='thing')
!"
有没有办法让我可以用 argparse 做到这一点?我已经寻找了一些不同的选择,但它们似乎都没有真正提供我所追求的.我想我可以通过制作 3 个不同的 ArgumentParsers 然后将参数传递给每个人来做一些麻烦事,尽管这听起来有点恶心.
Is there a way that I can do this with argparse? I've looked for a few different options, but none of them really seem to provide what I'm after. I guess I could do some jiggery with making 3 distinct ArgumentParsers and then passing on the arguments to each of them, though that sounds a bit gross.
还有更好的选择吗?
推荐答案
首先是一个历史记录 - 子解析器不是可选的,它们仍然不是 Python2.它们在 Py3 中是可选的这一事实是几年前引入的一个错误.所需参数的测试发生了变化,并且子解析器(一种位置)陷入了困境.如果操作正确,您应该必须将子解析器显式设置为不需要.
First a historical note - subparsers were not optional, and they still aren't in Python2. The fact that they are optional in Py3 is something of a bug that was introduced several years ago. There was a change in the test for required arguments, and subparsers (a kind of positional) fell through the cracks. If done right you should have had to explicitly set subparsers as not-required.
子解析器的行为不像其他非必需参数、带有 nargs='?'
或标记为不带 required
参数的参数.
Subparsers don't behave like other non-required arguments, ones with nargs='?'
or flagged without the required
parameter.
无论如何,您的sp.default
定义了将放入command
dest 中的值,但它不会触发a_parser代码>.
command='a'
永远不会被评估".
In any case, your sp.default
defines the value that will be put in the command
dest, but it does not trigger the use of a_parser
. That command='a'
is never 'evaluated'.
使用 parse_known_args
可能允许您使用 a_parser
贬值剩余的字符串.
The use of parse_known_args
might allow you to devaluate the remaining strings with a_parser
.
没有任何参数,我们可以:
Without any arguments, we can do:
In [159]: args, extras = parser.parse_known_args([])
In [160]: args
Out[160]: Namespace(command='a')
In [161]: extras
Out[161]: []
然后有条件地运行a_parser
(如果命令是'a'但没有'thing')
Then conditionally run a_parser
(if command is 'a' but no 'thing')
In [163]: a_parser.parse_args(extras,namespace=args)
Out[163]: Namespace(command='a', thing='thing')
但是如果我尝试包含一个 --thing
值:
But if I try to include a --thing
value:
In [164]: args, extras = parser.parse_known_args('--thing ouch'.split())
usage: ipython3 [-h] {a,b} ...
ipython3: error: argument command: invalid choice: 'ouch' (choose from 'a', 'b')
它尝试将ouch"解析为子解析器名称.主解析器对 --thing
参数一无所知.
It tries to parse the 'ouch' as subparser name. The main parser doesn't known anything about the --thing
argument.
正如我在今天的另一个 argparse
问题中所解释的,顶级解析器会解析输入,直到找到适合子解析器"命令的内容(或者在本示例中引发错误).然后它将解析传递给子解析器.之后它不会继续解析.
As I explained in the other argparse
question today, the toplevel parser parses the inputs until it finds something that fits the 'subparsers' command (or in this example raises an error). Then it passes the parsing to the subparser. It does not resume parsing after.
如何设置使用 Argparse 模块和 Python 2.7 的默认子解析器
我对这个 Py2 请求的回答可能对你有用.我首先使用没有子解析器的解析器运行 parse_known_args
,然后有条件地运行处理子解析器的第二个解析器.
My answer to this Py2 request might work for you. I first run a parse_known_args
with a parser that doesn't have subparsers, and conditionally run a second parser that handles the subparsers.
In [165]: firstp = argparse.ArgumentParser()
In [166]: args, extras = firstp.parse_known_args('--thing ouch'.split())
In [167]: args
Out[167]: Namespace()
如果 extras
没有 'a' 或 'b' 调用 a_parser
(或者只需查看 sys.argv[1:]
> 直接):
If extras
doesn't have 'a' or 'b' call a_parser
(alternatively just look at sys.argv[1:]
directly):
In [168]: extras
Out[168]: ['--thing', 'ouch']
In [169]: a_parser.parse_args(extras)
Out[169]: Namespace(thing='ouch')
或修改 extras
以包含缺少的 subparser 命令:
Or modify extras
to include the missing subparser command:
In [170]: extras = ['a']+extras
In [171]: parser.parse_args(extras)
Out[171]: Namespace(command='a', thing='ouch')
无论如何,optional
子解析器在argparse
中没有得到很好的开发.这是前一段时间所做更改的副作用,而不是经过深思熟虑的功能.
In any case, optional
subparsers is not well developed in argparse
. It's the side effect of a change made a while back, rather than a well thought out feature.
这篇关于你如何让 argparse 选择一个默认的子解析器?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!