Argparse:具有可变参数的选项的可选参数

Posted

技术标签:

【中文标题】Argparse:具有可变参数的选项的可选参数【英文标题】:Argparse: Optional argument with choices that have variable arguments 【发布时间】:2020-03-16 09:29:38 【问题描述】:

我有一个正在尝试改进的 CLI。我想做的是有一个带有 3 个选项的可选参数,根据您的选择,您需要为该选项输入某些参数。

例如:

--create dog DOG_NAME DOG_BREED
OR
--create cat CAT_NAME
OR
--create fish FISH_BREED FISH_TANK

等等

所以这看起来有点像:

parser.add_argument("--create", help="Create an animal", choices=["dog", "cat", "fish"])

但是我如何为每个选项设置不同的必需参数?我必须使用子解析器吗?

编辑:使用稍微不同的架构并让它工作。

parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(title="actions", dest="subcmd")
subp_create = subparsers.add_parser("create", description="Create a Dog, Cat, or Fish")
subp_delete = subparsers.add_parser("delete", description="Delete a Dog, Cat, or Fish")

subp_create.add_argument("--dog", help="Create a Dog", nargs=2, metavar=(DOG_NAME, DOG_BREED))
#etc.

args = parser.parse_args()
handle_args(args)

def handle_args(args):
    if args.subcmd == "create":
        if args.dog:
            dog_name = args.dog[0]
            dog_breed = args.dog[1]
            #Do whatever you need

【问题讨论】:

这可能有用:***.com/questions/19414060/… 类似但不完全一样。如果我将其应用于上面的示例,我需要所有可能参数的位置参数,即parser.add_argument("dog_name") no? 是的,subparser 是要走的路。 subparsers 参数实际上是一个带有“选择”的位置(不是像你那样标记的参数),并且对于每个选择,一个解析器都有自己的一组参数(是否需要)。 如果你坚持使用'--create',你需要在解析后测试其他参数。 【参考方案1】:

看起来这可能使用子解析器,但您也可以尝试使用 click。在我的系统上运行的示例:

#!/usr/bin/env python3

import click

@click.group('parent')
def parent():
    pass

@parent.group('create')
def create():
    pass

@create.command()
@click.argument('name')
@click.argument('breed')
def dog(name, breed):
    print(f'Dog: name: breed')

@create.command()
@click.argument('name')
def cat(name):
    print(f'Cat: name')

@create.command()
@click.argument('breed')
@click.argument('tank')
def fish(breed, tank):
    print(f'Fish of breed in tank')

if __name__ == '__main__':
    parent()

运行时:

$ ./click_test.py --help
Usage: click_test.py [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  create

$ ./click_test.py create --help
Usage: click_test.py create [OPTIONS] COMMAND [ARGS]...

Options:
  --help  Show this message and exit.

Commands:
  cat
  dog
  fish

然后再往下

$ ./click_test.py create dog
Usage: click_test.py create dog [OPTIONS] NAME BREED
Try "click_test.py create dog --help" for help.

Error: Missing argument "NAME".
$ ./click_test.py create dog Fido Labrador
Dog: Fido: Labrador

实际上我之前对点击并没有那么感兴趣——我认为对于我想要的一些复杂案例来说它太有限了——但它实际上对于这个案例来说非常好。

【讨论】:

我可以支持 Click 的案例。我已经在生产环境中使用过它几次,并且是一个非常可靠的解决方案。 感谢您的解决方案!我确实尝试过使用 Click,但实际上为 cli 使用了一些不同的模式,并且能够提出适合我需要的东西。我会用我所做的更新我的帖子。【参考方案2】:

尝试传递用引号括起来的多个参数列表,例如:

--create dog "DOG_NAME DOG_BREED"

你也可以用逗号分隔参数

--create dog DOG_NAME,DOG_BREED

使用split() 获取参数列表。

【讨论】:

感谢您的回复。我想我是在问如何根据已经存在的参数来获得不同的必需参数。即 root 命令是相同的 - 在本例中为 --create - 但根据您选择的选项,将有额外的必需参数。 我认为你必须在你的程序逻辑中实现它。为什么不直接调用--create dog--create cat 并为每个调用适当的逻辑呢? 我可以这样做,但如果可能的话,我想这样做。即使没有其他原因,也只是为了学习。 恐怕 Argparse 无法帮助您实现这一目标。我很确定除了将算法放入代码中之外别无他法。创建一个子解析器是一个很好的开始。

以上是关于Argparse:具有可变参数的选项的可选参数的主要内容,如果未能解决你的问题,请参考以下文章

可变参数后元组中的可选函数参数

C++ 宏的可选参数

如何在 argparse 中使用带有 nargs='*' 参数的可选位置参数?

Argparse - 子解析器中位置参数之前的可选参数

使用不需要指定输出文件名的可选参数运行 argparse

Python 用可变数量的位置参数和可选参数装饰方法