使用Python Argparse支持任意数量的相关参数



我想支持命令行接口,用户可以在其中声明任意数量的示例,其中一个或多个输入文件对应于每个示例。这样的东西:

$ myprogram.py 
      --foo bar 
      --sample1 input1.tsv 
      --sample2 input2a.tsv input2b.tsv input2c.tsv 
      --sample3 input3-filtered.tsv 
      --out output.tsv

这个想法是选项键将匹配模式--sample(d+),每个键将以选项值的形式消耗所有后续参数,直到遇到下一个---前缀的标志为止。对于明确声明的参数,这是argparse模块支持nargs='+'选项的常见用例。但是,由于我需要支持任意数量的参数,因此我无法明确声明它们。

parse_known_args命令将使我访问所有用户供给参数,但是那些未明确声明的参数不会将其分组为索引数据结构。为此,我需要仔细检查参数列表,请向前看,看看多少随后的值对应于当前标志,等等。

有什么办法可以解析这些选项,而无需基本上重新实现参数的大部分(几乎(解析器(几乎(?

如果您可以使用略有不同的语法生活,即:

$ myprogram.py 
  --foo bar 
  --sample input1.tsv 
  --sample input2a.tsv input2b.tsv input2c.tsv 
  --sample input3-filtered.tsv 
  --out output.tsv

参数名称不包含数字,但仍执行分组,请尝试以下操作:

parser.add_argument('--sample', action='append', nargs='+')

它产生列表的列表,即。--sample x y --sample 1 2将产生Namespace(sample=[['x', 'y'], ['1', '2']])

正如我在评论中提到的:

import argparse
argv = "myprogram.py 
      --foo bar 
      --sample1 input1.tsv 
      --sample2 input2a.tsv input2b.tsv input2c.tsv 
      --sample3 input3-filtered.tsv 
      --out output.tsv"
parser = argparse.ArgumentParser()
parser.add_argument('--foo')
parser.add_argument('--out')
for x in range(1, argv.count('--sample') + 1):
    parser.add_argument('--sample' + str(x), nargs='+')
args = parser.parse_args(argv.split()[1:])

给出:

print args
Namespace(foo='bar', out='output.tsv', sample1=['input1.tsv'], sample2=['input2a.tsv', 'input2b.tsv', 'input2c.tsv'], sample3=['input3-filtered.tsv'])

使用Real sys.argv,您可能必须用稍长于' '.join(sys.argv).count('--sample')

替换argv.count

这种方法的主要缺点是自动帮助生成不会涵盖这些领域。

在单独的参数值中制作该数字或键并在嵌套列表中收集相关参数会更简单。

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--foo')
parser.add_argument('--out')
parser.add_argument('--sample', nargs='+', action='append', metavar=('KEY','TSV'))
parser.print_help()
argv = "myprogram.py 
      --foo bar 
      --sample 1 input1.tsv 
      --sample 2 input2a.tsv input2b.tsv input2c.tsv 
      --sample 3 input3-filtered.tsv 
      --out output.tsv"
argv = argv.split()
args = parser.parse_args(argv[1:])
print(args)

生产:

1031:~/mypy$ python3 stack44267794.py -h
usage: stack44267794.py [-h] [--foo FOO] [--out OUT] [--sample KEY [TSV ...]]
optional arguments:
  -h, --help            show this help message and exit
  --foo FOO
  --out OUT
  --sample KEY [TSV ...]
Namespace(foo='bar', out='output.tsv', 
    sample=[['1', 'input1.tsv'], 
            ['2', 'input2a.tsv', 'input2b.tsv', 'input2c.tsv'], 
            ['3', 'input3-filtered.tsv']])

关于收集一般key:value对的问题。argparse中没有什么可以直接支持这一点。已经建议了各种各样的事情,但所有这些都归结为自己解析。

是否可以使用ArgParse捕获一组任意的可选参数?

您添加了每键参数的数量是可变的。这排除了处理'-sample1 = input1'作为简单字符串。

argparse已扩展了众所周知的POSIX命令行标准。但是,如果您想超越这一点,请准备好在(sys.argv(之前或argparse之后处理参数(parse_known_args extras(。

很可能有可能通过单击而不是argparse来做您正在寻找的事情。

引用:

$单击_

单击是用于创建美丽命令行的Python软件包 与必要的代码尽可能少的合并方式接口。 这是"命令行界面创建套件"。很高 可配置但带有明智的默认设置。

它旨在使编写命令行工具的过程快速,并且 乐趣,同时也阻止了无法造成的任何挫败感 实施预期的CLI API。

单击三点:

  • 命令的任意嵌套
  • 自动帮助页生成
  • 在运行时支持子命令的懒惰加载

    在http://click.pocoo.org/

  • 上阅读文档

单击的重要功能之一是能够构造子命令的能力(有点像使用git或image magic covert(,这应该使您可以将命令行构造为:

myprogram.py 
  --foo bar 
  --sampleset input1.tsv 
  --sampleset input2a.tsv input2b.tsv input2c.tsv 
  --sampleset input3-filtered.tsv 
  combinesets --out output.tsv

甚至:

myprogram.py 
  --foo bar 
  process input1.tsv 
  process input2a.tsv input2b.tsv input2c.tsv 
  process input3-filtered.tsv 
  combine --out output.tsv

可能更清洁的是,在这种情况下,您的代码将具有称为 --foo--out的参数,以及称为 processcombine进程的功能,将在指定的输入文件(s(中调用,并没有参数。

最新更新