如何用nargs =' +'解析几个位置参数

时间:2016-11-17 09:34:27

标签: python python-3.x parameter-passing argparse

这是我想要实现的目标的简短摘要:

  • 获取一个或多个(表格)文件
  • 寻找一个特定的字符串键(目前只有一个键,但我可以设想扩展它以接受多个键)
  • 与键匹配的行,提取给定位置或位置范围内的字符。

因此,在理想的世界中,我希望以下列方式运行我的脚本,它们都是有效的用例:

python myscript.py file1 file2 file3 "key" 10
python myscript.py file1 file2 "key" 10 12
python myscript.py file1 "key" 10 12
python myscript.py file1 "key" 10

鉴于我试过的用例:

parser = argparse.ArgumentParser()
parser.add_argument("files", nargs='+', help="input files")
parser.add_argument("gene", help="gene of interest")
parser.add_argument("pos", nargs='+', type=int, help="position(s) to analyze")

""" Validate pos """
if len(args.pos) > 2:
    sys.exit("Positions argument needs to be a single integer or two integers denoting a range!")

...

# in some other function
if len(args.pos) == 1:
    key = row[SIND][args.pos[0]]
elif len(args.pos) == 2:
    key = row[SIND][args.pos[0] : args.pos[1]]
else:
    print(args.pos, len(args.pos))
    sys.exit("args.pos assertion failed!")

当只有一个整数但是当我发送两个整数来分析范围时,它不起作用。在后一种情况下,"键"被解释为一个文件,因此我得到FileNotFoundError: [Errno 2] No such file or directory: 'IGHV4-39'

问题1:是否可以标记或指示位置参数,以便在files参数结束且gene开始时告诉argparse?我不想让它们成为可选参数,因为如果省略这三个参数中的任何一个,则脚本的逻辑是不完整的。

问题2:将pos参数分成两部分是否有用;取一个整数的pos,取两个整数的范围,然后使它们以某种方式排他?

有什么想法吗?

2 个答案:

答案 0 :(得分:4)

回答问题1

“是否可以标记...位置参数?”好吧,如果你这样做,那么他们就不再是位置论证了!因为所有位置参数都是通过处于适当位置而不是通过标记来定义的。

我认为你真正需要的只是required选项,而不是尝试使用位置参数太聪明。你的目标是创建一个非常聪明的界面,无论输入如何,或者一个可预测的界面并产生良好的错误信息,它可以神奇地找出你想要的东西吗?

我可以在这一点上讽刺,因为我过去花了太多时间做第一次而不只是做第二次。

为什么不这样做:

test.py

import argparse

parser = argparse.ArgumentParser()

parser.add_argument('--files', required=True, nargs='+')
parser.add_argument('--genes', required=True, nargs='+')
parser.add_argument(
    '--pos', required=True, nargs='+', type=int, help="position(s) to analyze")

opts = parser.parse_args()
print(dir(parser))

print('files: %s, genes: %s, poses: %s' % (
    opts.files, opts.genes, opts.pos))

所以:

$ python test.py
usage: test.py [-h] --files FILES [FILES ...] --genes GENES [GENES ...] --pos
           POS [POS ...]
test.py: error: the following arguments are required: --files, --genes, --pos

$ python test.py --files file1 file2 --genes xzy --pos 2 1
files: ['file1', 'file2'], genes: ['xzy'], poses: [2, 1]

回答问题2

你不是在问“这里最好的界面是什么”吗?当然,这是你需要决定的事情。我的建议:保持简单。为什么不这样做:

parser.add_argument('--start', '-s', required=True, nargs=1, type=int)
parser.add_argument('--end', '-e', nargs=1, type=int)

opts = parser.parse_args()
if opts.end is None:
    opts.end = opts.start + 1

答案 1 :(得分:1)

以下是sys.argv解析的快速实现:

In [97]: txt='file1 file2 file3 "key" 10 12'
In [98]: argv=txt.split()
In [99]: argv
Out[99]: ['file1', 'file2', 'file3', '"key"', '10', '12']
In [104]: files,rows,key=[],[],None
In [105]: for a in argv[::-1]:
     ...:     try:
     ...:         rows.append(int(a))
     ...:     except ValueError:
     ...:         if key is None: key=a
     ...:         else: files.append(a)
     ...:         
In [106]: files
Out[106]: ['file3', 'file2', 'file1']
In [107]: rows
Out[107]: [12, 10]
In [108]: key
Out[108]: '"key"'

您甚至可以使用parse_known_args来处理其他标记的参数,并将此逻辑应用于解析extras

argparse从左到右处理参数;你的位置逻辑更适合逆向。标志(optionals)在参数字符串之间提供明确定义的分隔符。没有它们,解析多个+参数是不可能的。第一个'+'是贪婪的(想到regex行为),并抓住所有。在为参数分配字符串时,它不会检查类型。在分配字符串后发生类型转换(例如int)。