【问题标题】:How do you get argparse to choose a default subparser?你如何让 argparse 选择一个默认的子解析器?
【发布时间】:2018-04-08 08:36:25
【问题描述】:

我在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',不是我所期望的,也就是说,“哦,是的,用户没有在命令行上提供任何参数,但我知道这应该被处理a_parser。这里是Namespace(command='a', thing='thing')!”

有没有办法让我可以用 argparse 做到这一点?我已经寻找了一些不同的选择,但它们似乎都没有真正提供我所追求的。我想我可以制作 3 个不同的 ArgumentParsers,然后将参数传递给每个参数,虽然这听起来有点恶心。

还有更好的选择吗?

【问题讨论】:

  • 您可以研究像 cliffclick 这样的命令行框架,它们通常为此类设计提供更好的支持。
  • 更好地使用docopt

标签: python argparse


【解决方案1】:

首先是历史记录 - 子解析器不是可选的,它们仍然不在 Python2 中。它们在 Py3 中是可选的这一事实是几年前引入的一个错误。所需参数的测试发生了变化,子解析器(一种位置)从裂缝中消失了。如果做得对,您应该必须将子解析器显式设置为不需要。

子解析器的行为不像其他非必需参数,带有nargs='?' 或没有required 参数的标记。

无论如何,您的sp.default 定义了将放入command dest 的值,但它不会触发a_parser 的使用。 command='a' 永远不会被“评估”。

使用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')

它尝试将“哎哟”解析为子解析器名称。主解析器对 --thing 参数一无所知。

正如我在今天的另一个argparse 问题中解释的那样,顶级解析器解析输入,直到找到适合“子解析器”命令的内容(或在此示例中引发错误)。然后它将解析传递给子解析器。之后它不会恢复解析。

Add top level argparse arguments after subparser args

How to Set a Default Subparser using Argparse Module with Python 2.7

我对这个 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 中没有得到很好的开发。这是不久前进行的更改的副作用,而不是经过深思熟虑的功能。

【讨论】:

    猜你喜欢
    • 2014-08-31
    • 2017-02-21
    • 2017-09-27
    • 2022-09-24
    • 1970-01-01
    • 2013-12-21
    • 2021-12-13
    • 2018-03-21
    • 1970-01-01
    相关资源
    最近更新 更多