python argparse - 带选项的可选append参数

Ste*_*eve 17 python argparse

我有一个脚本,我要求用户提供要执行的预定义操作的列表.我还希望能够在用户没有定义任何内容时采用特定的操作列表.然而,似乎试图将这两者结合在一起是不可能的.

当用户不提供参数时,他们会收到默认选项无效的错误

acts = ['clear','copy','dump','lock']
p = argparse.ArgumentParser()
p.add_argument('action', nargs='*', action='append', choices=acts, default=[['dump', 'clear']])
args = p.parse_args([])
>>> usage: [-h] [{clear,copy,dump,lock} [{clear,copy,dump,lock} ...]]
: error: argument action: invalid choice: [['dump', 'clear']] (choose from 'clear', 'copy', 'dump', 'lock')
Run Code Online (Sandbox Code Playgroud)

当它们确定一组动作时,结果命名空间将用户的动作附加到默认值,而不是替换默认值

acts = ['clear','copy','dump','lock']
p = argparse.ArgumentParser()
p.add_argument('action', nargs='*', action='append', choices=acts, default=[['dump', 'clear']])
args = p.parse_args(['lock'])
args
>>> Namespace(action=[['dump', 'clear'], ['dump']])
Run Code Online (Sandbox Code Playgroud)

jco*_*ado 16

您需要的是使用自定义argparse.Action,如下例所示:

import argparse

parser = argparse.ArgumentParser()

class DefaultListAction(argparse.Action):
    CHOICES = ['clear','copy','dump','lock']
    def __call__(self, parser, namespace, values, option_string=None):
        if values:
            for value in values:
                if value not in self.CHOICES:
                    message = ("invalid choice: {0!r} (choose from {1})"
                               .format(value,
                                       ', '.join([repr(action)
                                                  for action in self.CHOICES])))

                    raise argparse.ArgumentError(self, message)
            setattr(namespace, self.dest, values)

parser.add_argument('actions', nargs='*', action=DefaultListAction,
                    default = ['dump', 'clear'],
                    metavar='ACTION')

print parser.parse_args([])
print parser.parse_args(['lock'])
Run Code Online (Sandbox Code Playgroud)

脚本的输出是:

$ python test.py 
Namespace(actions=['dump', 'clear'])
Namespace(actions=['lock'])
Run Code Online (Sandbox Code Playgroud)


Cir*_*四事件 6

我最终做了以下事情:

  • append
  • 将空列表添加到可能的选择中,否则空输入会中断
  • 无默认值
  • 之后检查空列表并在这种情况下设置实际的默认值

例子:

parser = argparse.ArgumentParser()
parser.add_argument(
    'is',
    type=int,
    choices=[[], 1, 2, 3],
    nargs='*',
)

args = parser.parse_args(['1', '3'])
assert args.a == [1, 3]

args = parser.parse_args([])
assert args.a == []
if args.a == []:
    args.a = [1, 2]

args = parser.parse_args(['1', '4'])
# Error: '4' is not valid.
Run Code Online (Sandbox Code Playgroud)


n1r*_*1r3 5

在文档(http://docs.python.org/dev/library/argparse.html#default)中说:

对于nargs等于?的位置参数 或*,不存在命令行参数时使用默认值。

然后,如果我们这样做:

acts = ['clear','copy','dump','lock']
p = argparse.ArgumentParser()
p.add_argument('action', nargs='*', choices=acts, default='clear')    
print p.parse_args([])
Run Code Online (Sandbox Code Playgroud)

我们得到了我们的期望

Namespace(action='clear')
Run Code Online (Sandbox Code Playgroud)

问题是当您将列表作为默认列表时。但是我已经在文档中看到了

parser.add_argument('bar', nargs='*', default=[1, 2, 3], help='BAR!')
Run Code Online (Sandbox Code Playgroud)

所以,我不知道:-(

无论如何,这是一种解决方法,可以完成您想要的工作:

import sys, argparse
acts = ['clear','copy','dump','lock']
p = argparse.ArgumentParser()
p.add_argument('action', nargs='*', choices=acts)
args = ['dump', 'clear'] # I set the default here ... 
if sys.argv[1:]:
    args = p.parse_args()
print args
Run Code Online (Sandbox Code Playgroud)