python argparse-带选项的可选追加参数

2024-06-02 14:00:23 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个脚本,要求用户提供要执行的预定义操作的列表。我还希望当用户没有定义任何东西时,能够假定一个特定的操作列表。然而,似乎不可能同时做到这两个。

当用户没有给出参数时,他们会收到一个错误,默认选择无效

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

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

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']])

Tags: 用户addlock列表定义argparseargsaction
3条回答

您需要什么可以使用定制的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'])

脚本的输出是:

$ python test.py 
Namespace(actions=['dump', 'clear'])
Namespace(actions=['lock'])

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

For positional arguments with nargs equal to ? or *, the default value is used when no command-line argument was present.

那么,如果我们这样做了:

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

我们得到了我们所期望的

Namespace(action='clear')

问题是当您将列表作为默认值时。 但我在医生那里见过

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

所以,我不知道

不管怎样,这里有一个解决方法,可以完成您想要的工作:

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

您可以测试用户是提供操作(在这种情况下,将其作为必需的position参数进行分析),还是不提供操作(在这种情况下,将其作为默认的可选参数进行分析):

import argparse
import sys

acts = ['clear', 'copy', 'dump', 'lock']
p = argparse.ArgumentParser()
if sys.argv[1:]:
    p.add_argument('action', nargs = '*', choices = acts)
else:
    p.add_argument('--action', default = ['dump', 'clear'])

args = p.parse_args()
print(args)

运行时,将生成以下结果:

% test.py 
Namespace(action=['dump', 'clear'])
% test.py lock
Namespace(action=['lock'])
% test.py lock dump
Namespace(action=['lock', 'dump'])

您可能还有其他的解析选项。在这种情况下,可以使用parse_known_args解析其他选项,然后在第二次传递中处理unknown参数:

import argparse

acts = ['clear', 'copy', 'dump', 'lock']
p = argparse.ArgumentParser()
p.add_argument('--foo')
args, unknown = p.parse_known_args()
if unknown:
    p.add_argument('action', nargs = '*', choices = acts)
else:
    p.add_argument('--action', default = ['dump', 'clear'])

p.parse_args(unknown, namespace = args)
print(args)

运行时,将生成以下结果:

% test.py 
Namespace(action=['dump', 'clear'], foo=None)
% test.py --foo bar
Namespace(action=['dump', 'clear'], foo='bar')
% test.py lock dump
Namespace(action=['lock', 'dump'], foo=None)
% test.py lock dump --foo bar
Namespace(action=['lock', 'dump'], foo='bar')

相关问题 更多 >