我有一个脚本,我要求用户提供要执行的预定义操作的列表。我还希望能够在用户没有定义任何内容时采用特定的操作列表。然而,似乎试图将这两者结合在一起是不可能的。
当用户不提供参数时,他们会收到默认选项无效的错误
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']])
答案 0 :(得分:15)
您可以使用自定义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'])
答案 1 :(得分:4)
在文档(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([])
我们得到了我们的期望
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
答案 2 :(得分:3)
您可以测试用户是否正在提供操作(在这种情况下将其解析为必需的位置参数),或者不提供任何操作(在这种情况下将其解析为默认的可选参数):
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')
答案 3 :(得分:1)
由于您传递给argparse的“action ='append'”参数,正在追加操作。
删除此参数后,用户传递的参数将自行显示,但程序在没有传递参数时会抛出错误。
在第一个参数中添加' - '前缀以最懒的方式解决这个问题。
acts = ['clear','copy','dump','lock']
p = argparse.ArgumentParser()
p.add_argument('--action', nargs='*', choices=acts, default=[['dump', 'clear']])
args = p.parse_args()
这种方法的缺点是用户传递的选项现在必须以' - action'开头,例如:
app.py --action clear dump copy
答案 4 :(得分:1)
我最终做了以下事情:
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.