2013-03-20 21 views
9

我想用​​做出以下两种方式来使用一些代码:如何定义两个位置参数的互斥组?

./tester.py all 
./tester.py name someprocess 

即指定或name一些额外的字符串,要么是all

我试图实现如下:

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

为什么你想避免SUP解析器?这看起来完全像一个子分析器问题! – 2013-03-20 17:06:51

+0

他们已经在suparsers上运作。我想保持它浅薄......但如果没有其他解决方案,我会在两个层次上与子分析器一起尝试。 – Alex 2013-03-20 17:07:44

+0

将'all'改为'--all'和'name'为'--name'。 – hughdbrown 2013-03-20 17:48:27

回答

-2

这可能是你在找什么:

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

传递然后--name将在列表中的一个值要求,并将它们存储为列表。 “

+1

正确格式化代码,'--name'中有一些错误。 – 2013-07-29 00:02:24

0

”OR name with some additional string。“

位置参数不能采取额外的字符串

我认为你最好的解决办法是(名为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()) 

$蟒蛇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 
0

我同意这看起来就像是一个子分析器问题,并且如果你不想通过使用来使它成为可选参数和--name,从我一个建议是只是忽略allname干脆,并使用以下语义:

  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 
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 
8

的问题是一岁,但因为所有的答案提出一个不同的语法,我给的东西更接近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之后做自己的测试通常比让​​做一些特殊的事更简单。

+0

+1最简单的,我忘记了“选择”,而且我没有仔细阅读,OP在'name'参数后只需要一个进程名。 – justhalf 2014-03-24 07:12:05

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