你如何让 argparse 选择默认的子解析器?
How do you get argparse to choose a default subparser?
我在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)
我可以用三种不同的方式调用它:
$ 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'
,不是我期望的,也就是说,"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 做到这一点吗?我已经寻找了几个不同的选项,但其中 none 似乎确实提供了我所追求的。我想我可以制作 3 个不同的 ArgumentParsers,然后将参数传递给每个 ArgumentParsers,尽管这听起来有点恶心。
有更好的选择吗?
首先是历史记录 - 子解析器不是可选的,它们仍然不在 Python2 中。事实上,它们在 Py3 中是可选的,这是几年前引入的一个错误。对所需参数的测试发生了变化,子解析器(一种位置)从裂缝中掉了下来。如果做得对,您应该必须明确地将子解析器设置为不需要。
子解析器的行为不像其他非必需参数,那些带有 nargs='?'
或没有 required
参数的标记。
无论如何,您的 sp.default
定义了将放入 command
dest 的值,但它不会触发 a_parser
的使用。 command='a'
永远不会是 'evaluated'.
parse_known_args
的使用可能允许您使用 a_parser
.
贬值剩余的字符串
没有任何参数,我们可以这样做:
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')
In [163]: a_parser.parse_args(extras,namespace=args)
Out[163]: Namespace(command='a', thing='thing')
但是如果我尝试包含一个 --thing
值:
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
参数一无所知。
正如我今天在另一个 argparse
问题中所解释的那样,顶层解析器解析输入,直到找到适合 'subparsers' 命令的内容(或者在本例中引发错误)。然后它将解析传递给子解析器。之后它不会恢复解析。
Add top level argparse arguments after subparser args
我对这个 Py2 请求的回答可能对你有用。我首先 运行 一个 parse_known_args
带有一个没有子解析器的解析器,并且有条件地 运行 一个处理子解析器的第二个解析器。
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:]
):
In [168]: extras
Out[168]: ['--thing', 'ouch']
In [169]: a_parser.parse_args(extras)
Out[169]: Namespace(thing='ouch')
或修改 extras
以包含缺少的子解析器命令:
In [170]: extras = ['a']+extras
In [171]: parser.parse_args(extras)
Out[171]: Namespace(command='a', thing='ouch')
无论如何,optional
子解析器在 argparse
中没有得到很好的开发。这是前一段时间所做更改的副作用,而不是经过深思熟虑的功能。
我在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)
我可以用三种不同的方式调用它:
$ 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'
,不是我期望的,也就是说,"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 做到这一点吗?我已经寻找了几个不同的选项,但其中 none 似乎确实提供了我所追求的。我想我可以制作 3 个不同的 ArgumentParsers,然后将参数传递给每个 ArgumentParsers,尽管这听起来有点恶心。
有更好的选择吗?
首先是历史记录 - 子解析器不是可选的,它们仍然不在 Python2 中。事实上,它们在 Py3 中是可选的,这是几年前引入的一个错误。对所需参数的测试发生了变化,子解析器(一种位置)从裂缝中掉了下来。如果做得对,您应该必须明确地将子解析器设置为不需要。
子解析器的行为不像其他非必需参数,那些带有 nargs='?'
或没有 required
参数的标记。
无论如何,您的 sp.default
定义了将放入 command
dest 的值,但它不会触发 a_parser
的使用。 command='a'
永远不会是 'evaluated'.
parse_known_args
的使用可能允许您使用 a_parser
.
没有任何参数,我们可以这样做:
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')
In [163]: a_parser.parse_args(extras,namespace=args)
Out[163]: Namespace(command='a', thing='thing')
但是如果我尝试包含一个 --thing
值:
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
参数一无所知。
正如我今天在另一个 argparse
问题中所解释的那样,顶层解析器解析输入,直到找到适合 'subparsers' 命令的内容(或者在本例中引发错误)。然后它将解析传递给子解析器。之后它不会恢复解析。
Add top level argparse arguments after subparser args
我对这个 Py2 请求的回答可能对你有用。我首先 运行 一个 parse_known_args
带有一个没有子解析器的解析器,并且有条件地 运行 一个处理子解析器的第二个解析器。
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:]
):
In [168]: extras
Out[168]: ['--thing', 'ouch']
In [169]: a_parser.parse_args(extras)
Out[169]: Namespace(thing='ouch')
或修改 extras
以包含缺少的子解析器命令:
In [170]: extras = ['a']+extras
In [171]: parser.parse_args(extras)
Out[171]: Namespace(command='a', thing='ouch')
无论如何,optional
子解析器在 argparse
中没有得到很好的开发。这是前一段时间所做更改的副作用,而不是经过深思熟虑的功能。