我想使用argparse
来制作一些代码,用于以下两种方式:
./tester.py all
./tester.py name someprocess
即。指定all
或name
并附加一些字符串。
我试图按如下方式实施:
import argparse
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument('all', action='store_true', \
help = "Stops all processes")
group.add_argument('name', \
help = "Stops the named process")
print parser.parse_args()
给了我一个错误
ValueError: mutually exclusive arguments must be optional
知道怎么做对吗?在这种情况下,我也想避免使用子解析器。
答案 0 :(得分:11)
这个问题已经有一年了,但由于所有的答案都提出了不同的语法,我会给OP提供更接近的东西。
首先,OP代码的问题:
位置store_true
没有意义(即使允许)。它不需要参数,因此始终为True
。给予所有人“全部”将产生error: unrecognized arguments: all
。
另一个参数接受一个值并将其分配给name
属性。它不接受额外的process
值。
关于mutually_exclusive_group
。甚至在parse_args
之前就会引发该错误消息。对于这样一个有意义的群体,所有替代方案都必须是可选的。这意味着要么拥有--
旗帜,要么是nargs
等于?
或*
的位置。在小组中不止一个这样的位置是没有意义的。
使用--all
和--name
的最简单方法是这样的:
p=argparse.ArgumentParser()
p.add_argument('mode', choices=['all','name'])
p.add_argument('process',nargs='?')
def foo(args):
if args.mode == 'all' and args.process:
pass # can ignore the process value or raise a error
if args.mode == 'name' and args.process is None:
p.error('name mode requires a process')
args = p.parse_args()
foo(args) # now test the namespace for correct `process` argument.
接受的命名空间如下所示:
Namespace(mode='name', process='process1')
Namespace(mode='all', process=None)
choices
模仿subparsers参数的行为。在parse_args
之后进行自己的测试通常比使argparse
做一些特别的事情更简单。
答案 1 :(得分:0)
"或者用一些额外的字符串命名。"
位置参数不能采取额外的字符串
我认为最适合您的解决方案是(名为test.py):
import argparse
p = argparse.ArgumentParser()
meg = p.add_mutually_exclusive_group()
meg.add_argument('-a', '--all', action='store_true', default=None)
meg.add_argument('-n', '--name', nargs='+')
print p.parse_args([])
print p.parse_args(['-a'])
print p.parse_args('--name process'.split())
print p.parse_args('--name process1 process2'.split())
print p.parse_args('--all --name process1'.split())
$ python test.py
Namespace(all=None, name=None)
Namespace(all=True, name=None)
Namespace(all=None, name=['process'])
Namespace(all=None, name=['process1', 'process2'])
usage: t2.py [-h] [-a | -n NAME [NAME ...]]
t2.py: error: argument -n/--name: not allowed with argument -a/--all
答案 2 :(得分:0)
我同意这看起来与子解析器问题完全相同,如果您不希望使用--all
和--name
使其成为可选参数,那么我的一个建议就是只是完全忽略all
和name
,并使用以下语义:
tester.py
,请停止所有进程。tester.py
,请仅停止这些进程。可以使用以下方法完成:
import argparse, sys
parser = argparse.ArgumentParser()
parser.add_argument('processes', nargs='*')
parsed = parser.parse(sys.argv[1:])
print parsed
表现如下:
$ python tester.py Namespace(processes=[]) $ python tester.py proc1 Namespace(processes=['proc1'])
或者,如果您坚持自己的语法,则可以创建自定义类。实际上你没有“互斥组”的情况,因为我假设如果指定了all
,你将忽略其余的参数(即使name
是其他参数之一) ,并且当指定name
时,之后的任何其他内容都将被视为进程的名称。
import argparse
import sys
class AllOrName(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
if len(values)==0:
raise argparse.ArgumentError(self, 'too few arguments')
if values[0]=='all':
setattr(namespace, 'all', True)
elif values[0]=='name':
if len(values)==1:
raise argparse.ArgumentError(self, 'please specify at least one process name')
setattr(namespace, 'name', values[1:])
else:
raise argparse.ArgumentError(self, 'only "all" or "name" should be specified')
parser = argparse.ArgumentParser()
parser.add_argument('processes', nargs='*', action=AllOrName)
parsed = parser.parse_args(sys.argv[1:])
print parsed
具有以下行为:
$ python argparse_test.py name usage: argparse_test.py [-h] [processes [processes ...]] argparse_test.py: error: argument processes: please specify at least one process name $ python argparse_test.py name proc1 Namespace(name=['proc1'], processes=None) $ python argparse_test.py all Namespace(all=True, processes=None) $ python argparse_test.py host usage: argparse_test.py [-h] [processes [processes ...]] argparse_test.py: error: argument processes: only "all" or "name" should be specified $ python argparse_test.py usage: argparse_test.py [-h] [processes [processes ...]] argparse_test.py: error: argument processes: too few arguments
答案 3 :(得分:0)
import argparse
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-a','--all', action='store_true', \
help = "Stops all processes")
group.add_argument('-n','--name', \
help = "Stops the named process")
print parser.parse_args()
./ tester.py -h
usage: zx.py [-h] (-a | -n NAME)
optional arguments:
-h, --help show this help message and exit
-a, --all Stops all processes
-n NAME, --name NAME Stops the named process
答案 4 :(得分:-2)
这可能就是你要找的东西:
group.add_argument('--all', dest=is_all, action='store_true')
group.add_argument('--name', dest=names, nargs='+')
传递--name将在列表中要求一个值并将它们存储为列表。