Python 如何添加可选或一次性参数?

Python 如何添加可选或一次性参数?,python,argparse,Python,Argparse,如何添加可选且不能多次指定的参数 有效期: $ ./my.py $ ./my.py --arg MyArgValue 无效: $ ./my.py --arg MyArgValue --arg ThisIsNotValid 如果我添加如下参数: parser.add_argument('--arg', type=str) 无效示例导致字符串无效。我预计会出现语法分析器错误。您可以使用它来获取出现此错误的次数,如果不止一个,则会产生错误 “append”-存储一个列表,并将每个参数值追加到列表

如何添加可选且不能多次指定的参数

有效期:

$ ./my.py
$ ./my.py --arg MyArgValue
无效:

$ ./my.py --arg MyArgValue --arg ThisIsNotValid
如果我添加如下参数:

parser.add_argument('--arg', type=str)

无效示例导致字符串
无效。我预计会出现语法分析器错误。

您可以使用它来获取出现此错误的次数,如果不止一个,则会产生错误

“append”-存储一个列表,并将每个参数值追加到列表中。这对于允许多次指定选项非常有用。用法示例:

有关“附加”的文档可在此处找到,以了解更多详细信息:

不幸的是,argparse没有更简单的方法。这大概是因为这不是一个足够常见的用例。通常,此计数用于布尔情况,如详细模式。当您有附加字符串时,例如带有include路径的编译器等,它们通常都会得到尊重

也许,您也可以使用nargs,只使用args.arg_name[0],而忽略其余部分。在这里,您可以找到关于以下内容的
nargs
文档:


这感觉像是一个老套的解决方案,但可以满足您的需求。使用
追加

append操作将从命令行创建一个列表,其中包含调用此参数的所有时间的所有值。如果此列表的长度大于一,则表示出现错误


通过这种方式,您可以从命令行获取值,如果有多个值,您可以将其视为错误并通知用户。

创建一个自定义操作,如果同一参数出现两次,则会引发异常。当解析器捕捉到异常时,它将打印用法和格式良好的错误消息

import argparse

class Highlander(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        if getattr(namespace, self.dest, None) is not None:
            raise argparse.ArgumentError(self, 'There can be only one.')
        setattr(namespace, self.dest, values)

parser = argparse.ArgumentParser()
parser.add_argument('-f', action=Highlander)
print (parser.parse_args('-f 1 -f 2'.split()))

我测试了一个使用
互斥组的解决方案
。其思想是定义一个包含
--arg
两次的组。解析器维护一个
seen\u non\u default\u actions
列表,并在对新参数字符串执行操作之前检查是否存在独占组冲突。如果此列表中已存在
--arg
,则下一次调用将与其冲突,并引发错误

这种方法有几个问题

1) 无法将现有操作添加到新的互斥组。在本文中,我举例说明了一个围绕这个问题的混乱局面。它还引用了一个建议的补丁,使这更容易

2) 当前
parse_args
将操作添加到
seed_non_default_actions
列表中,然后检查冲突。这意味着第一个
--arg
将与其自身冲突。解决办法是切换顺序。首先检查冲突,然后将操作添加到列表中

import my_argparse as argparse  # use a customized argparse
parser = argparse.ArgumentParser(prog="PROG",
    formatter_class=argparse.MultiGroupHelpFormatter)
# use a custom formatter than can handle overlapping groups

action = parser.add_argument('--arg', help='use this argument only once')
# define a group with two copies of this action as per patch issue10984
group = parser.add_mutually_exclusive_group(action, action)
args  = parser.parse_args()
使用各种参数调用时,生成:

$ python3 test.py -h
usage: PROG [-h] [--arg ARG | --arg ARG]

optional arguments:
  -h, --help  show this help message and exit
  --arg ARG   use this argument only once

$ python3 test.py --arg test
Namespace(arg='test')

$ python3 test.py --arg test --arg next
usage: PROG [-h] [--arg ARG | --arg ARG]
PROG: error: argument --arg: not allowed with argument --arg

不过,我想知道,这是否是一种足够直观的说法,‘只使用这个论点一次’。用法行
[--arg arg |--arg arg]
是否传达了这一点?错误消息
参数--arg:notallowed with argument--arg是否足够清晰?

我仍然需要实际值“MyArgValue”,而不是计数。是的,与Seth首先发布的内容非常相似。我知道我可以编写代码来检查这一点。最简单的方法是检查args.myarg是否为数组。我希望有一种更优雅的方式,因为在我看来这是一个如此简单的用例。@Alex实际上,如果没有“附加”操作,您只会得到给定选项(而不是列表)的最后一个值,因此无法知道用户是否多次给出该选项。至少在这种情况下,您可以判断它是否被多次给出,并将其作为错误捕获。只需再次调试:一个包含一个元素的列表,最后一个参数的值。我猜argparse的行为不是很直观。但是Python 2.7。@Alex如果我不使用
action='append'
,我就不会得到一个列表。你是对的,我在玩其他选项时把我的测试工具搞砸了:)在我的Python安装(2.7)上,我没有得到一个包含一个元素(
['thisNotValid']
)的列表,而是一个字符串(
'thisNotValid'
)当我复制并粘贴您的代码时。更正:已编辑的问题。为什么您的用户会多次使用此选项?argparse的默认行为是允许以任何顺序使用标志,包括重复它们。但是除了使用
count
append
操作之外,重复几乎没有什么用处——除了可能纠正以前的用法。@hpaulj:错了。因此,我花了好几个小时对脚本进行故障排除。我个人认为,对于这种覆盖先前指定的选项的argparse行为,没有什么有意义的用例。argparse只是通过参数字符串工作。如果它找到一个
-o
字符串,它将尝试执行指定给该字符串的操作。如果它再次遇到该字符串,它将执行相同的操作,而不引用以前所做操作的记录。这对于
count
append
操作很方便,但在您的情况下并不方便。不过,它会跟踪已处理的位置。但是这些都是“没有名字”的参数,必须以特定的顺序出现,不能重复。很酷,这似乎是迄今为止最优雅的解决方案!如果您不想依赖于
默认值
,您可以在命名空间中存储一个自定义计数器或标志,例如
setattr(namespace,self.dest+'used',True)
,并对其进行测试。我不想这么说,但这肯定比我的解决方案好。正如@hpaulj所说的,这只在没有默认值的情况下有效。修复
\uuuu调用中的检查,我们可以修复以下问题:更改:
如果getattr(namespace,self.dest,None)不是None
如果(self.default不是None,self.default!=getattr(namespace,self.dest,None))或(self.default是None,getattr(namespace,self.dest,None)不是None)
import my_argparse as argparse  # use a customized argparse
parser = argparse.ArgumentParser(prog="PROG",
    formatter_class=argparse.MultiGroupHelpFormatter)
# use a custom formatter than can handle overlapping groups

action = parser.add_argument('--arg', help='use this argument only once')
# define a group with two copies of this action as per patch issue10984
group = parser.add_mutually_exclusive_group(action, action)
args  = parser.parse_args()
$ python3 test.py -h
usage: PROG [-h] [--arg ARG | --arg ARG]

optional arguments:
  -h, --help  show this help message and exit
  --arg ARG   use this argument only once

$ python3 test.py --arg test
Namespace(arg='test')

$ python3 test.py --arg test --arg next
usage: PROG [-h] [--arg ARG | --arg ARG]
PROG: error: argument --arg: not allowed with argument --arg