【问题标题】:How to add optional or once arguments?如何添加可选参数或一次参数?
【发布时间】:2013-09-03 20:46:35
【问题描述】:

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

有效:

$ ./my.py
$ ./my.py --arg MyArgValue

无效:

$ ./my.py --arg MyArgValue --arg ThisIsNotValid

如果我添加如下参数:

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

无效示例生成字符串ThisIsNotValid。我预计会出现解析器错误。

【问题讨论】:

  • 在我的 python 安装 (2.7) 上,当我复制和粘贴您的代码时,我没有得到一个包含一个元素 (['ThisIsNotValid']) 的列表,而是一个字符串 ('ThisIsNotValid')。
  • 正确:已编辑问题。
  • 为什么您的用户可能会多次使用此选项? argparse 的默认行为是允许以任何顺序使用标志,包括重复它们。但除了 countappend 动作之外,重复几乎没有用 - 除了可能纠正之前的使用。
  • @hpaulj:错了。因此,我发现自己对脚本进行了数小时的故障排除。对于这种覆盖先前指定选项的 argparse 行为,我个人认为没有任何有意义的用例。
  • argparse 仅通过参数字符串起作用。如果它找到-o 字符串,它会尝试执行对该字符串指定的操作。如果它再次遇到那个字符串,它会做同样的事情,而不参考它之前做过的事情的记录。这对于 countappend 操作很方便,但在您的情况下不方便。但是,它确实会跟踪它处理了哪些位置。但这些都是“无名”论点,必须以特定顺序出现,不得重复。

标签: python argparse


【解决方案1】:

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

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()))

【讨论】:

  • 酷,这似乎是迄今为止最优雅的解决方案!
  • 如果您不想依赖 defaultNone,您可以在命名空间中存储自定义计数器或标志,例如setattr(namespace, self.dest+'used', True),并对此进行测试。
  • 我不想这么说,但这绝对比我的解决方案好。
  • 正如@hpaulj 所说,这仅在没有默认值的情况下才有效。修复 __call__ 中的检查,我们可以解决这个问题:将:if getattr(namespace, self.dest, None) is not None 更改为 if (self.default is not None and self.default != getattr(namespace, self.dest, None)) or (self.default is None and getattr(namespace, self.dest, None) is not None)
【解决方案2】:

这感觉像是一个 hacky 解决方案,但会得到你想要的。使用appendaction

parser.add_argument('-arg', type=str, action='append')
args = parser.parse_args()
if len(args.arg) > 1:
    sys.exit("Only one argument is allowed for '-arg'")
elif len(args.arg) == 1: # elif is because it is valid for the length to be 0
    args.arg = args.arg[0]

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

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

【讨论】:

  • 我知道我可以编写代码来检查这一点。最简单的方法是检查 args.myarg 是否是一个数组。我希望有一种更优雅的方式,因为在我看来这是一个如此简单的用例。
  • @Alex 实际上,如果没有“附加”操作,您只会获得给定选项(不是列表)的最后一个值,因此无法知道用户是否多次给出该选项.至少在这种情况下,您可以判断它是否被多次给出并将其作为错误捕获。
  • 刚刚再次调试:一个包含一个元素的列表,即最后一个参数的值。我猜 argparse 的行为不是很直观。不过是 Python 2.7。
  • @Alex 如果我不使用action='append',我不会得到列表。
  • 你说得对,我搞砸了我的测试工具,玩弄其他选项 :)
【解决方案3】:

您可以使用它来获取它的出现次数,如果超过一次则产生错误。

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

import argparse
import sys
parser = argparse.ArgumentParser()
parser.add_argument('-arg', type='str', action='append')
args = parser.parse_args()
if len(args.arg) > 1:
    sys.exit('Invalid')
MyArgValue = args.arg[0]

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

http://docs.python.org/dev/library/argparse.html#action

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

也许,您也可以使用 nargs 并仅使用 args.arg_name[0] 并忽略其余部分。您可以在这里找到nargs 的相关文档:

http://docs.python.org/dev/library/argparse.html#nargs

【讨论】:

  • 我仍然需要实际值“MyArgValue”,而不是计数。
  • 是的,非常类似于赛斯首先发布的内容。
【解决方案4】:

我测试了一个使用mutually_exclusive_group 的解决方案。这个想法是定义一个包含--arg 两次的组。解析器维护一个seen_non_default_actions 列表,并在对新参数字符串采取操作之前检查该列表是否存在排他性组冲突。如果--arg 已经存在于这个列表中,那么下一次调用将与它发生冲突,并引发错误。

这种方法存在几个问题。

1) 现有操作不能添加到新的互斥组。在https://stackoverflow.com/a/18555236/901925 中,我说明了一个解决这个问题的方法。它还引用了一个建议的补丁,使这更容易。

2) 目前parse_args 将操作添加到seen_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] 是否传达了这一点?错误信息argument --arg: not allowed with argument --arg 够清楚吗?

【讨论】:

    猜你喜欢
    • 2021-11-04
    • 2010-09-23
    • 2014-08-09
    • 1970-01-01
    • 2020-08-06
    • 1970-01-01
    • 2012-04-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多