【问题标题】:Argparse: How to switch from default parser to a different subparser when a certain optional argument is given?Argparse:当给出某个可选参数时,如何从默认解析器切换到不同的子解析器?
【发布时间】:2022-09-24 00:10:59
【问题描述】:

我有一个通常使用 2 个位置参数和一堆可选参数调用的脚本。

script.py <file1> <file2> 

我想添加另一个子解析器,当我传递一个可选参数时应该调用它。

script.py -file_list <files.list>

基本上,我要求的是当-file_list 被传递时,解析器不应该寻找file1file2。我不希望默认情况需要另一个选项来调用它(因为默认情况已经在使用中,因此我不想破坏它)。

我尝试保持默认解析器不变并为-file_list 创建子解析器。但是解析器仍然需要位置参数file1file2

示例代码(这不像我想要的那样工作):

args = argparse.ArgumentParser()

#default arguments
args.add_argument(\"file1\", type=str)
args.add_argument(\"file2\", type=str)

#subparser for file_list
file_list_sp = args.add_subparsers()
file_list_parser = file_list_sp.ad_parser(\"-file_list\")
file_list_parser.add_argument(\"file_list\")

all_args = args.parse_args()

也许我需要为默认情况创建一个单独的子解析器;但所有子解析器似乎都需要一个额外的命令来调用它们。我希望在未传递 -file_list 时自动调用默认情况

  • -fil_list 不是有效的子解析器名称。当使用子解析器时,很难有一个 \'default\' 的情况。您需要为每个备选方案定义一个子解析器。在尝试做一些新奇的事情之前,先练习记录的风格。
  • @hpaulj 它可以是,如果你改变前缀字符。但你是对的,坚持既定的惯例比尝试不同的东西要好。 (我怀疑更改前缀字符的能力是为了允许复制现有界面,而不是鼓励命令行界面中的“创新”。)
  • @chepner您的怀疑确实是正确的。 script.py &lt;file1&gt; &lt;file2&gt; 表单已存在。我需要添加一个新选项,用户可以在其中传递一个只有文件对列表的文件。因此,原始命令应继续按原样工作。
  • 我认为没有任何好的基于argparse 的解决方案可以解决这个问题,除非手动重新实现大部分参数处理。子命令和普通的顶级位置参数并不能很好地配合使用。您可能能够为 -file_list 选项定义自定义操作,或对解析的参数进行后处理,但 argparse(开箱即用)无法处理您想要实现的逻辑。
  • 仍然需要 2 个位置。 subparsers 是另一个位置。

标签: python argparse


【解决方案1】:

你在传递其他选项时提到了,所以我认为保留argparse 的动机很好。假设没有其他位置,您可以尝试:

In [23]: parser = argparse.ArgumentParser()    
In [24]: parser.add_argument('--other'); # other optionals
In [25]: parser.add_argument('--filelist');   
In [26]: parser.add_argument('files', nargs='*');

这接受“--filelist”,而不需要位置文件,(结果为空列表):

In [27]: parser.parse_args('--filelist alist'.split())
Out[27]: Namespace(other=None, filelist='alist', files=[])

其他文件 - 但将该列表限制为 2 需要您在解析后进行自己的测试:

In [28]: parser.parse_args('file1 file2'.split())
Out[28]: Namespace(other=None, filelist=None, files=['file1', 'file2'])

但它也接受这两种形式。同样,您自己的后解析代码将不得不整理出冲突的消息:

In [29]: parser.parse_args('file1 file2 --filelist xxx'.split())
Out[29]: Namespace(other=None, filelist='xxx', files=['file1', 'file2'])

你必须处理两者都没有提供的情况:

In [30]: parser.parse_args('--other foobar'.split())
Out[30]: Namespace(other='foobar', filelist=None, files=[])

帮助:

In [32]: parser.print_help()
usage: ipykernel_launcher.py [-h] [--other OTHER] [--filelist FILELIST]
                             [files ...]

positional arguments:
  files

optional arguments:
  -h, --help           show this help message and exit
  --other OTHER
  --filelist FILELIST

所以我创建的内容接受两种形式的输入,但不限制它们。

我尝试使用互斥组,但这仅适用于nargs='?'。我曾经以为nargs='*'在一个小组工作,但要么我的记忆错了,要么有一个补丁改变了事情。 m-x-group 中的位置必须具有 'required=False' 值。

subparsers 实际上是一种特殊的positional。因此,如果您使用 'prog file1 file2 {cmd1, cmd2}' 创建了解析器,它仍然会在检查第三个字符串之前需要 2 个文件名。所有positionals,包括subparsers 都按位置处理,而不是按值处理。标记的参数 (optional) 可以按任何顺序出现,但不会覆盖 positionals

如果您首先定义subparsers,那么第一个位置必须是这些命令之一。 subparsers 不是必需的(默认情况下),但这不会改变其他位置的处理。

【讨论】:

    猜你喜欢
    • 2020-09-26
    • 2017-09-27
    • 2019-05-04
    • 2014-08-31
    • 2018-04-08
    • 1970-01-01
    • 2012-04-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多