15

我想用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

知道怎么做吗?在这种情况下,我也想避免使用子解析器。

4

5 回答 5

15

这个问题已经有一年了,但是由于所有答案都暗示了不同的语法,所以我会给出更接近 OP 的内容。

首先,OP代码的问题:

位置store_true没有意义(即使它是允许的)。它不需要任何参数,所以它总是True. 给予“全部”将产生error: unrecognized arguments: all

另一个参数采用一个值并将其分配给name属性。它不接受process附加值。

关于mutually_exclusive_group. 该错误消息甚至在parse_args. 为了使这样一个组有意义,所有的选择都必须是可选的。这意味着要么有一个--标志,要么是一个nargs等于?或的位置*。并且在小组中拥有多个这样的位置是没有意义的。

使用--alland的最简单替代方法--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模仿子解析器参数的行为。之后做自己的测试parse_args通常比做argparse一些特别的事情更简单。

于 2014-03-24T06:06:24.383 回答
1
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
于 2017-04-22T10:32:09.223 回答
0

我同意这看起来完全像一个子解析器问题,并且如果您不想通过使用--alland使其成为可选参数--name,我的一个建议就是完全忽略allandname并使用以下语义:

  1. 如果tester.py在没有任何参数的情况下调用,则停止所有进程。
  2. 如果tester.py使用一些参数调用,则仅停止那些进程。

可以使用以下方法完成:

import argparse, sys
parser = argparse.ArgumentParser()
parser.add_argument('processes', nargs='*')
parsed = parser.parse(sys.argv[1:])
print parsed

其行为如下:

$ python tester.py
命名空间(进程=[])
$ python tester.py proc1
命名空间(进程=['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 名称
用法:argparse_test.py [-h] [进程[进程...]]
argparse_test.py:错误:参数进程:请指定至少一个进程名称

$ python argparse_test.py 名称 proc1
命名空间(名称=['proc1'],进程=无)

$ python argparse_test.py 全部
命名空间(全部=真,进程=无)

$ python argparse_test.py 主机
用法:argparse_test.py [-h] [进程[进程...]]
argparse_test.py:错误:参数过程:只应指定“全部”或“名称”

$蟒蛇argparse_test.py
用法:argparse_test.py [-h] [进程[进程...]]
argparse_test.py:错误:参数过程:参数太少
于 2014-03-24T05:15:39.997 回答
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())

$蟒蛇测试.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
于 2014-03-24T04:15:36.740 回答
-2

这可能是您正在寻找的:

group.add_argument('--all', dest=is_all, action='store_true')
group.add_argument('--name', dest=names, nargs='+')

传递 --name 然后将需要列表一个值并将它们存储为列表。

于 2013-04-04T12:25:16.343 回答