【问题标题】:Argparse: two positional arguments with nargs='+'argparse:两个位置参数,nargs='+'
【发布时间】:2015-07-25 23:01:40
【问题描述】:

我正在尝试在图像之间进行数学运算。我已经定义(我的真实代码的简化版本):

parser = argparse.ArgumentParser(description='Arithmetic operations on images')
parser.add_argument("input1", metavar='input1', action='store',
      help='list of input images to operate with', nargs="+", type=str)
parser.add_argument("operation", metavar='operation', action='store', type=str, 
      help='type of operation (+,-,*,/) to be done', nargs=1)
parser.add_argument("input2",metavar='input2', action='store', nargs="+", 
      type=str, help='image (or value) with which to perform the operation on input1')

这段代码,产生:

arith.py -h
usage: arith.py [-h] input1 [input1 ...] operation input2 [input2 ...]

所以它确实理解 input1 可以包含一个或多个元素,操作将是单个元素,而 input2 可以是任意数量的元素。

当然,问题在于有两个位置参数和不确定数量的元素,argparse 混淆了什么是什么。我尝试在“操作”中添加选择=[“+”、“-”、“*”、“/”],以便它知道在哪里进行分离,但似乎 argparse 无法做到这一点。实际上,在 argparse 文档中,谈论 nargs='*' 您可以阅读:

请注意,使用 nargs='*' 拥有多个位置参数通常没有多大意义

我认为我可以将 args.input1、args.operation 和 args.input2 加在一起,然后将自己分开寻找“+”、“-”、“/”、“*”,但在做如此丑陋的事情之前,我想到了挖掘集体思想。

【问题讨论】:

  • 我不确定argparse 是否适合您在这里所做的工作。直接通过sys.argv 可能会更容易。
  • 嗨,凯尔伍德。实际上,我使用 argparse 解析 sys.argv。这为我“免费”提供了用户帮助,它为我完成了所有检查类型和现有变量。直接执行 sys.argv 就像我将 input1、operation 和 input2 汇集在一起​​,然后将自己分开的解决方案。可行,但丑陋;)。还是谢谢!
  • argparse 可以构造这样的帮助消息,但这并不意味着它实际上可以按照您想要的方式解析参数。如果我打电话给arith.py a b c d e f g,哪个是operation?它可以是bf 中的任何一个。 argparse 没有内置任何类型的回溯模式匹配器;它只是以贪婪的方式从左到右处理参数。
  • 可能有更清晰的方法来构建论点。 input1input2 是如何处理的? input1kth 元素是否使用指定的运算符与 input2kth 元素配对?或者您是否计算两个列表的笛卡尔积并将运算符应用于产品的每个元素?还是别的什么?
  • 如果 len(input1) = len(input2) 他们配对。如果 len(input2) = 1,则对 input1 的所有元素以及 input2 的单个元素进行操作。

标签: python argparse


【解决方案1】:

将字符串分配给位置时,解析器仅区分以前缀 char 开头的字符串(例如“-”)和其他字符串。它无法区分表示“数字”的字符串和表示“操作”的字符串。实际上它执行这个正则表达式操作:

re.match('(A+)(A)(A+)','AAAAAAAAA')

这将产生(AAAAAA),(A),(A)。它为最后 2 组分配足够的字符串以满足它们的规范,并将其余的分配给第一个。

所以你需要某种“标志”来标记第一个列表的结尾。

我认为这是与argparse 最接近的:

parser.add_argument("input1", nargs="+", type=int)
parser.add_argument("-o", "--operation", choices=['+','minus','*','/'] )
parser.add_argument("input2", nargs="+", type=int)

应该转向

PROG 1 3 4 -o + 5 6 7
PROG 1 3 4 -o+ 5 6 7
PROG 1 3 4 --operation=+ 5 6 7

进入(我认为)

namespace(input1=[1,3,4], operation='+', input2=[5,6,7])

请注意choices 的列表不包含“-”。那是因为解析器将其视为前缀字符。可能有一种方法可以将其作为参数值潜入其中,但我不会花时间找到它。

我在解析器中将input1 值转换为整数。之后你可以这样做。当然也可以制作花车。

我省略了type=straction='store'等默认参数。


但也许更好的解决方案是将所有值作为 1 个列表,然后自己拆分。至少有了这 3 个参数,您并没有充分利用 argparse 的力量。

alist = ['1','2','3','+','4','5','6']
i = <find index of '+-/*'>
input1 = alist[:i]
operations = alist[i]
input2 = alsits[i+1:]

【讨论】:

  • 感谢您的努力。过去,我能够将“-”偷偷带入非位置参数的唯一方法是:-o“-”之前有一个空格的字符串,因此 - 被视为字符串的一部分
  • # 之类的其他内容指定为 prefix_char,可能会释放 - 以用作参数。
  • 是的,hpaulj,这就是我遵循的方法,正如我在 OP 中暗示的那样。看来我要求的太多了。不过,为了让用户清楚起见,我只是留下了三个论点。解析后,我再次将它们加入并正确拆分。
【解决方案2】:

如果您使用“必需的可选”参数,您可以完成这项工作。如果从左操作数更改为操作更改为右操作数,则需要在命令行上显示选项。例如。

import argparse

parser = argparse.ArgumentParser(description='Process some integers.')
parser.add_argument("--left-operands", "-l", nargs="+", required=True)
parser.add_argument("--right-operands", "-r", nargs="+", required=True)
parser.add_argument("--operation", "-o", choices=["+", "-", "*", "/"], required=True)

argline = "-l 1 2 -o + -r 3 4"

print(parser.parse_args(argline.split(" ")))

【讨论】:

  • 谢谢,Dunes,但不是我想要的。我希望参数是位置的。否则,我会回到将 input1、input2 和 operation 放在一起并在内部分离它们的想法。
猜你喜欢
  • 2016-07-19
  • 2021-09-02
  • 2017-02-23
  • 2011-05-27
  • 2017-03-31
  • 1970-01-01
  • 1970-01-01
  • 2012-08-31
  • 2018-08-10
相关资源
最近更新 更多